JustCode – Makes syncing your settings across machines a breeze!

As many of you know, I’m affiliated with Telerik as one of their insiders. Telerik is also a friend of CodeBetter. I’ve used the JustCode for several years now. I want to make you aware of a really cool and useful new feature in JustCode – the ability to sync settings across multiple machines. The feature is called JustCode Cloud and it’s a breeze to setup.

The following image illustrates the new JustCode Options Dialog:

In order to make this all work, you need to establish a Telerik Account and agree to terms of service. After that, when you change your settings, assuming you have an active internet connection, your settings will be synced to the cloud. you can also sync on demand when you need to pull your settings from the cloud.

If you are looking for a Visual Studio productivity tool that has a light footprint with simple to use features, check out JustCode.

Thinking you have a ton of new keyboard shortcuts to learn? Well…JustCode thought of that. In an instant, you can easily display the keyboard mappings:

Code templates and customizations are extremely easy. If you are looking for a new Visual Studio productivity tool, check out Telerik’s JustCode!!

Posted in Telerik, Uncategorized | Tagged , | Leave a comment

Documenting your ASP.Net Web API’s

I’ve picked something up where Yao Huang Lin of Microsoft left off. For preliminary material, check out his blog and check out his posts on generating documentation.

In one of his later posts, he suggested creating a help controller. This is where I’ve picked things up. In Yao’s solution, he’s rendering html-based views. While that works well and makes for a nice presentation, I wanted to remain within the mode of just returning data, whether it is JSON or XML. Before continuing on with this post, please be sure to read Yao’s posts on the topic as I will be picking up where he left off on this post where he talks about other implemenations.

The first thing we need is a help controller.  Here is the one I’ve created:

using System.Collections.Generic;
using System.Net;
using System.Web.Http;
using System.Web.Http.Description;

namespace WebAPI.Controllers
{
 [ApiExplorerSettings(IgnoreApi = true)]
 public class HelpController : ApiController
 {
  public List Get()
  {
   return APIDocumentationRepository.Get();
  }

  public APIEndPoint Get(string api)
  {
   return APIDocumentationRepository.Get(api);
  }
 }
}

Nothing all that complicated here. Like all good controllers, this one is thin – with just enough logic to expose and service the end points. I’ve created an APIDocumenationRepository Class to handle all of the data-related operations. One point to focus on is the attribute: [ApiExplorerSettings(IgnoreApi = true)]. We don’t want the help controller itself to appear in the documentation. No need to do that since in order to get to the help documentation, you need to know the help endpoint exists in the first place!

There are two endpoints: one to get all of the endpoints and another to get a specific endpoint. In my earlier posts, I was referencing a simple Products Controller. I’m continuing to use that same controller here. For review, here is the listing for that controller:

using System;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using WebApi.Models;

namespace WebApi.Controllers
{
 public class ProductsController : ApiController
 {
  /// <summary>
  /// Returns the Product Collection.
  /// </summary>
  /// <returns></returns>
  [Queryable]
  public IQueryable<Product> GetProducts()
  {
   return ProductsRepository.data.AsQueryable();
  }

  /// <summary>
  /// Returns an individual Product.
  /// </summary>
  /// <param name="id">The Product id.</param>
  /// <returns></returns>
  public Product GetProduct(int id)
  {
   try
   {
    return ProductsRepository.get(id);
   }
   catch (NotFoundException)
   {
    throw new HttpResponseException(new HttpResponseMessage()
    {
     StatusCode = System.Net.HttpStatusCode.NotFound
    });
   }
  }

  /// <summary>
  /// Deletes the Products Collection and reverts back to original state.
  /// </summary>
  /// <returns></returns>
  [HttpDelete]
  public void ResetProducts()
  {
   ProductsRepository.reset();
  }

  /// <summary>
  /// Deletes an individual Product.
  /// </summary>
  /// <param name="id">The Product id.</param>
  /// <returns></returns>
  public void DeleteProduct(int id)
  {
   try
   {
    ProductsRepository.delete(id);
   }
   catch (NotFoundException)
   {
    throw new HttpResponseException(new HttpResponseMessage()
    {
     StatusCode = System.Net.HttpStatusCode.NotFound
    });
   }
  }

  /// <summary>
  /// Updates an individual Product.
  /// </summary>
  /// <param name="product">The Product object.</param>
  /// <returns></returns>
  public void PutProduct(Product product)
  {
   ProductsRepository.update(product);
  }

  /// <summary>
  /// Creates a new Product.
  /// </summary>
  /// <param name="product">The Product object.</param>
  /// <returns></returns>
  public void PostProduct(Product product)
  {
   ProductsRepository.add(product);
  }
 }
}

There are a few changes from the earlier versions of this controller. As you can see, I’m using the XML Documentation features Yao talks about in his post. I’ve simply employed the technique he describes.

The next thing to cover is the APIDocumenationRepository Class. Here is the code for that class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;
using System.Web.Http;
using System.Web.Http.Description;

namespace WebAPI
{
 public class APIDocumentationRepository
 {
  public static APIEndPoint Get(string apiName) {
    return getAPIEndPoint(apiName);
  }

  public static List<APIEndPoint> Get()
  {

   var Controllers = GlobalConfiguration
       .Configuration
       .Services
       .GetApiExplorer()
       .ApiDescriptions
       .GroupBy(x => x.ActionDescriptor.ControllerDescriptor.ControllerName)
       .Select(x => x.First().ActionDescriptor.ControllerDescriptor.ControllerName)
       .ToList();
       
   var apiEndPoints = new List<APIEndPoint>();

   foreach (var controller in Controllers) {
      apiEndPoints.Add(getAPIEndPoint(controller));
   }
   
   return apiEndPoints;
  }

  static APIEndPoint getAPIEndPoint(string controller) {

   var apis = GlobalConfiguration
    .Configuration
    .Services
    .GetApiExplorer()
    .ApiDescriptions
    .Where(x => x.ActionDescriptor.ControllerDescriptor.ControllerName == controller);

   List<APIEndPointDetail> apiEndPointDetails = null; 

   if (apis.ToList().Count > 0)
   {

   apiEndPointDetails = new List<APIEndPointDetail>();
   foreach (var api in apis)
   {
    apiEndPointDetails.Add(getAPIEndPointDetail(api));
   } 
   }
   else
   {
    controller = string.Format("The {0} api does not exist.",controller);
   }
   return new APIEndPoint(controller,apiEndPointDetails);
  }

  static APIEndPointDetail getAPIEndPointDetail(ApiDescription api) {

   if (api.ParameterDescriptions.Count > 0)
   {
    var parameters = new List<APIEndPointParameter>();
    foreach (var parameter in api.ParameterDescriptions)
    {
     parameters.
     Add(new APIEndPointParameter(parameter.Name, parameter.Documentation, parameter.Source.ToString()));
    }
    return new APIEndPointDetail(api.RelativePath, api.Documentation, api.HttpMethod.Method, parameters);
   }
   else
   {
    return new APIEndPointDetail(api.RelativePath, api.Documentation, api.HttpMethod.Method);
   }
  }
 }

 [DataContract]
 public class APIEndPoint {
  [DataMember] public string Name { get; private set; }
  [DataMember] public List<APIEndPointDetail> APIEndPointDetails { get; private set; }

  public APIEndPoint(string name, List<APIEndPointDetail> apiEndPointDetails)
  {
    Name = name;
    APIEndPointDetails = apiEndPointDetails;
  }

 }

 [DataContract]
 public class APIEndPointDetail
 {
  [DataMember]
  public string RelativePath { get; private set; }
  [DataMember]
  public string Documentation { get; private set; }
  [DataMember]
  public string Method { get; private set; }
  [DataMember]
  public List<APIEndPointParameter> Parameters { get; private set; }

  public APIEndPointDetail(string relativePath, string documentation, string method, 
   List<APIEndPointParameter> parameters) : this(relativePath, documentation, method)
  {
   Parameters = parameters;
  }

  public APIEndPointDetail(string relativePath, string documentation, string method)
  {
   RelativePath = relativePath;
   Documentation = documentation;
   Method = method;
  }
 }

 [DataContract]
 public class APIEndPointParameter
 {
  [DataMember]
  public string Name { get; set; }
  [DataMember]
  public string Documentation { get; private set; }
  [DataMember]
  public string Source { get; private set; }

  public APIEndPointParameter(string name, string documentation, string source)
  {
   Name = name;
   Documentation = documentation;
   Source = source;
  }
 }
}

With the everything in place, including all of the things outlined in Yao’s post, with this url:
http://localhost:18950/api/help?api=Products – the following is the api documenation for the Products API:

{
   "Name":"Products",
   "APIEndPointDetails":[
      {
         "RelativePath":"api/Products",
         "Documentation":"Returns the Product Collection.",
         "Method":"GET"
      },
      {
         "RelativePath":"api/Products/{id}",
         "Documentation":"Returns an individual Product.",
         "Method":"GET",
         "Parameters":[
            {
               "Name":"id",
               "Documentation":"The Product id.",
               "Source":"FromUri"
            }
         ]
      },
      {
         "RelativePath":"api/Products",
         "Documentation":"Deletes the Products Collection and reverts back to original state.",
         "Method":"DELETE"
      },
      {
         "RelativePath":"api/Products/{id}",
         "Documentation":"Deletes an individual Product.",
         "Method":"DELETE",
         "Parameters":[
            {
               "Name":"id",
               "Documentation":"The Product id.",
               "Source":"FromUri"
            }
         ]
      },
      {
         "RelativePath":"api/Products",
         "Documentation":"Updates an individual Product.",
         "Method":"PUT",
         "Parameters":[
            {
               "Name":"product",
               "Documentation":"The Product object.",
               "Source":"FromBody"
            }
         ]
      },
      {
         "RelativePath":"api/Products",
         "Documentation":"Creates a new Product.",
         "Method":"POST",
         "Parameters":[
            {
               "Name":"product",
               "Documentation":"The Product object.",
               "Source":"FromBody"
            }
         ]
      }
   ]
}

And if XML is your thing, no problem. Simply set the content-type header to application/xml:

<APIEndPoint xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebAPI">
  <APIEndPointDetails>
    <APIEndPointDetail>
      <Documentation>Returns the Product Collection.</Documentation>
      <Method>GET</Method>
      <Parameters i:nil="true" />
      <RelativePath>api/Products</RelativePath>
    </APIEndPointDetail>
    <APIEndPointDetail>
      <Documentation>Returns an individual Product.</Documentation>
      <Method>GET</Method>
      <Parameters>
        <APIEndPointParameter>
          <Documentation>The Product id.</Documentation>
          <Name>id</Name>
          <Source>FromUri</Source>
        </APIEndPointParameter>
      </Parameters>
      <RelativePath>api/Products/{id}</RelativePath>
    </APIEndPointDetail>
    <APIEndPointDetail>
      <Documentation>Deletes the Products Collection and reverts back to original state.</Documentation>
      <Method>DELETE</Method>
      <Parameters i:nil="true" />
      <RelativePath>api/Products</RelativePath>
    </APIEndPointDetail>
    <APIEndPointDetail>
      <Documentation>Deletes an individual Product.</Documentation>
      <Method>DELETE</Method>
      <Parameters>
        <APIEndPointParameter>
          <Documentation>The Product id.</Documentation>
          <Name>id</Name>
          <Source>FromUri</Source>
        </APIEndPointParameter>
      </Parameters>
      <RelativePath>api/Products/{id}</RelativePath>
    </APIEndPointDetail>
    <APIEndPointDetail>
      <Documentation>Updates an individual Product.</Documentation>
      <Method>PUT</Method>
      <Parameters>
        <APIEndPointParameter>
          <Documentation>The Product object.</Documentation>
          <Name>product</Name>
          <Source>FromBody</Source>
        </APIEndPointParameter>
      </Parameters>
      <RelativePath>api/Products</RelativePath>
    </APIEndPointDetail>
    <APIEndPointDetail>
      <Documentation>Creates a new Product.</Documentation>
      <Method>POST</Method>
      <Parameters>
        <APIEndPointParameter>
          <Documentation>The Product object.</Documentation>
          <Name>product</Name>
          <Source>FromBody</Source>
        </APIEndPointParameter>
      </Parameters>
      <RelativePath>api/Products</RelativePath>
    </APIEndPointDetail>
  </APIEndPointDetails>
  <Name>Products</Name>
</APIEndPoint>

Enjoy…

JVP

Posted in ASP.NET Web API, ASPNET MVC 4 | 3 Comments

ASP.Net Web API Example Video Now Available

You can find the video here. The associated code can be found here.

In this video, I take you through some basics on REST and how it applies to the ASP.Net Web API and how the Web API  can be utilized by ASP.Net MVC 4.

A major topic I don’t cover in this video is security and using various approaches like encrypted tokens in the request header, oAuth, etc.  I will have that video posted in the next few weeks. Those samples will build upon this set of examples.

Enjoy

 

Posted in ASP.NET MVC 4, ASP.NET Web API, Visual Studio 2012 RC 1 | Leave a comment

ASP Web API examples – now updated with Release Candidate bits

You can find the bits here. If you haven’t downloaded the ASP.Net MVC 4 Release Candidate bits, you can find them here.

I greatly simplified this version. I removed the XML support in favor of exclusive JSON support. In addition, I refactored the httpclass and serialization classes to a separate project.

In the next few days, I’ll post a video that walks through the example in detail. A few other notes: I migrated the project to Visual Studio 2012 RC 1. In short, VS 2012 looks great and it is a great environment to work with. The good news as to this eample is that if you want to open this project in Visual Studio 2010 SP 1 – you can! I do have VS 2012 installed on my production machine and it works fine and has not caused any issues with system. Whether you choose to go down that road yourself, be sure you can assume the risk of needing to repave your machine!!

Posted in ASP.NET MVC 4, ASP.NET Web API | Leave a comment

Scott Hanselman’s 5/31/2012 visit to Philly.Net – the Video

We at Philly.Net were fortunate to host Scott Hanselman on 5/31 at Montgomery County Community College.  Scott’s topic was the Future of ASP.Net. Click here to view the video. Special thanks to Apprenda for making possible the Montgomery County Community College venue for Scott’s visit.

Posted in Philly Dot Net, Scott Hanselman | Leave a comment