Web Services : Useful Links to get started

There are a few things confounding me in my understanding of WebService development in C#

 

  1. Return types from action methods.

Two very interesting reads :

 

Return Type Example / Comments
1.ActionResult.

 

  • return Content(“AmlRequestResponse task not in state IsCompleted!”);
  • return this.Content(jsonString);
    
  • This is MVC specific
2.Product / IEnumerable<Product>
  • return products;
  • What’s the difference between this and using IHttpActionResult
3.IHttpActionResult
  • return Ok(product);
4.HttpResponseMessage
  • return Request.CreateResponse(HttpStatusCode.OK);
  • return Request.CreateResponse(HttpStatusCode.OK,
    response,
    JsonMediaTypeFormatter.DefaultMediaType);
5.String / async Task<string>
  • return “abhishek”;

 

  • For 2,3,4 if we return objects, then we get JSON response back
  • If we say return Ok(“bob”) then string “bob” gets returned.

 

  1. Routing By Verb

 

  • By default Web API chooses controller actions based on an HTTP Verb (RESTful approach). You can force it into an RPC mode (action name based), but you can’t combine these two in a single controller, and as it would throw an Ambiguous match exception.

 

  • To determine which action to invoke, the framework uses a routing table. The Visual Studio project template for Web API creates a default route:

routes.MapHttpRoute(
name: “API Default”,
routeTemplate: “api/{controller}/{id}”,
defaults: new { id = RouteParameter.Optional }
);

 

  • Each entry in the routing table contains a route template. The default route template for Web API is “api/{controller}/{id}”. In this template, “api” is a literal path segment, and {controller} and {id} are placeholder variables.

 

  • When the Web API framework receives an HTTP request, it tries to match the URI against one of the route templates in the routing table. If no route matches, the client receives a 404 error. For example, the following URIs match the default route:
    • /api/contacts
    • /api/contacts/1
    • /api/products/gizmo1

 

  • Once a matching route is found, Web API selects the controller and the action:
    • To find the controller, Web API adds “Controller” to the value of the {controller} variable.
    • To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name. For example, with a GET request, Web API looks for an action that starts with “Get…”, such as “GetContact” or “GetAllContacts”.  This convention applies only to GET, POST, PUT, and DELETE methods. It pretty much looks for anything starting with ‘Get..’ that matches the parameters passed
    • You can enable other HTTP methods by using attributes on your controller. We’ll see an example of that later.
    • Other placeholder variables in the route template, such as {id}, are mapped to action parameters.

 

  • Example #1. Suppose that you define the following controller:

public class ProductsController : ApiController
{
public void GetAllProducts() { }
public IEnumerable<Product> GetProductById(int id) { }
public HttpResponseMessage DeleteProduct(int id){ }
}

Here are some possible HTTP requests, along with the action that gets invoked for each:

HTTP Method URI Path Action Parameter
GET api/products GetAllProducts (none)
GET api/products/4 GetProductById 4
DELETE api/products/4 DeleteProduct 4
POST api/products (no match)

Notice that the {id} segment of the URI, if present, is mapped to the id parameter of the action. In this example, the controller defines two GET methods, one with an id parameter and one with no parameters.

Also, note that the POST request will fail, because the controller does not define a “Post…” method.

 

  • Example #2. Let’s say you’ve created a new subclass of ApiController called OrderController. WebAPI provides your OrderController with out-of-the-box support for the following URLs:

 

HTTP VERB URL DESCRIPTION
GET /api/order Returns all orders
GET /api/order/3 Returns details order #3
POST /api/order Create new order
PUT /api/order/3 Update order #3
DELETE /api/order/3 Delete order #3

 

The above is considered verb-based routing. The URLs above only contain thecontroller name and an optional id. So the Web API uses the HTTP verb of the request to determine the action method to execute in your ApiController subclass.

 

  1. Routing By Action Name

 

With the default routing template, Web API uses the HTTP method to select the action. However, you can also create a route where the action name is included in the URI:

routes.MapHttpRoute(
name: “ActionApi”,
routeTemplate: “api/{controller}/{action}/{id}”,
defaults: new { id = RouteParameter.Optional });

 

In this route template, the {action} parameter names the action method on the controller. With this style of routing, use attributes to specify the allowed HTTP methods. For example, suppose your controller has the following method:

public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}

In this case, a GET request for “api/products/details/1” would map to the Details method. This style of routing is similar to ASP.NET MVC, and may be appropriate for an RPC-style API.

You can override the action name by using the ActionName attribute. In the following example, there are two actions that map to “api/products/thumbnail/id. One supports GET and the other supports POST:

public class ProductsController : ApiController
{
[HttpGet]
[ActionName(“Thumbnail”)]
public HttpResponseMessage GetThumbnailImage(int id);

[HttpPost]
[ActionName(“Thumbnail”)]
public void AddThumbnailImage(int id);
}

  • Non-Actions

To prevent a method from getting invoked as an action, use the NonAction attribute. This signals to the framework that the method is not an action, even if it would otherwise match the routing rules.

// Not an action method.
[NonAction]
public string GetPrivateData() { … }

 

  1. References:

 

 

[1] http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

[2] http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection   –-> this link describes exactly how the framework matches a URI to a route, selects a controller, and then selects the action to invoke. good read

[3] http://blog.appliedis.com/2013/03/25/web-api-mixing-traditional-verb-based-routing/

[4] http://www.strathweb.com/2013/01/magical-web-api-action-selector-http-verb-and-action-name-dispatching-in-a-single-controller/

[5] http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/action-results

[6] http://thuru.net/2015/02/20/httpresponsemessage-vs-ihttpactionresult/

[7] http://stackoverflow.com/questions/21758615/why-should-i-use-ihttpactionresult-instead-of-httpresponsemessage

 

Curl Command (Linux)

$ curl http://teamonewebapiusage.azurewebsites.net/api/products
[{“Id”:1,”Name”:”Tomato Soup”,”Category”:”Groceries”,”Price”:1.0},{“Id”:2,”Name”:”Yo-yo”,”Category”:”Toys”,”Price”:3.75},{“Id”:3,”Name”:”Hammer”,”Category”:”Hardware”,”Price”:16.99}]

$ curl http://teamonewebapiusage.azurewebsites.net/api/products/3
{“Id”:3,”Name”:”Hammer”,”Category”:”Hardware”,”Price”:16.99}

 

Some more examples:

 

 

 

  • When we use curl at the command line to access websites, the traffic doesn’t show up in Fiddler. This is because curl doesn’t use the system proxy by default.  Try this:

 

 

Example from the Decision Service Web API

  • $ curl -x 127.0.0.1:8888 -H “Content-Type: application/json” -X POST -d @data.json http://localhost:29074/api/decision
    {“Action”:4,”EventId”:”26808b79af3741169863168040109301″,”TimeStamp”:”2016-02-18T09:16:20.2329418Z”}

 

Reference:

[1]  http://www.yilmazhuseyin.com/blog/dev/curl-tutorial-examples-usage/

[2] http://stackoverflow.com/questions/14978411/http-post-and-get-using-curl-in-linux

[3] http://stackoverflow.com/questions/18352190/why-i-get-411-length-required-error

Git : Syncing a Fork

1. Git Diff

Suppose git status looks like this.

gitstatus

  • git diff --staged will only show changes to files in the “staged” area.
    • So only changes to data.json  and /python/amlLatency.py  will be shown
  • git diff HEAD will show all changes to tracked files.
    • So changes to data.json,  /python/amlLatency.py  and /python/retrieveStreamingDataRedis.py will be shown
  • git diff
    • Only changes to python/retrieveStreamingDataRedis.py will be shown

2. Syncing  a Fork  – from GitHub.

  1. Open your fork repo on GitHub.
  2. Click on Pull Requests.
  3. Click on New Pull Request. By default, GitHub will compare the original with your fork, and there shouldn’t be nothing to compare if you didn’t make any changes.
  4. Click on switching the base (if no changes were made in the fork) or click Edit and switch the base manually. Now GitHub will compare your fork with the original, and you should see all the latest changes.
  5. Click on Create to create a pull request for this comparison and assign a predictable name to your pull request (e.g., Update from original).
  6. Click on Send pull request.
  7. Scroll down and click Merge pull request and finally Confirm merge (If your fork didn’t have any changes, you will be able to merge it automatically).

3. Syncing  a Fork  – from GitHub.

  • View existing remotes

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git remote -v
multiworldtesting https://github.com/multiworldtesting/decision.git (fetch)
multiworldtesting https://github.com/multiworldtesting/decision.git (push)
origin https://github.com/abgoswam/decision.git (fetch)
origin https://github.com/abgoswam/decision.git (push)

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git fetch multiworldtesting –> Interestingly this didn’t do anything for me. The reason being there were already local branches for ‘remotes/multiworldtesting/*’.  I went ahead and added another remote called ‘upstream’

  • Setting up a new remote (in this example not really needed, but setting up new remote still)

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git remote add upstream https://github.com/multiworldtesting/decision

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git fetch upstream
From https://github.com/multiworldtesting/decision
* [new branch] Declarative -> upstream/Declarative
* [new branch] demo -> upstream/demo

  • View remotes

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git remote -v
multiworldtesting https://github.com/multiworldtesting/decision.git (fetch)
multiworldtesting https://github.com/multiworldtesting/decision.git (push)
origin https://github.com/abgoswam/decision.git (fetch)
origin https://github.com/abgoswam/decision.git (push)
upstream https://github.com/multiworldtesting/decision (fetch)
upstream https://github.com/multiworldtesting/decision (push)

  • View branches

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git branch -va
* master 71a8dc2 fixed bug with asa due to lack of timestamp and ids on outcome and reward objects
remotes/multiworldtesting/Declarative f08fc46 MSN meeting

  • Sync with upstream (and fail): 

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git checkout master
M ClientDecisionServiceSample/Program.cs
M ClientDecisionServiceSample/SingleActionSamples.cs
Already on ‘master’
Your branch is up-to-date with ‘origin/master’.

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git merge upstream/master
Updating 71a8dc2..1175689
error: Your local changes to the following files would be overwritten by merge:
ClientDecisionServiceSample/Program.cs
Please, commit your changes or stash them before you can merge.
error: Your local changes to the following files would be overwritten by merge:
ClientDecisionServiceSample/SingleActionSamples.cs
Please, commit your changes or stash them before you can merge.
Aborting

  • Note how this failed because there were 2 files in my origin/master which are being edited.

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git status
On branch master
Your branch is up-to-date with ‘origin/master’.
Changes to be committed:
(use “git reset HEAD <file>…” to unstage)

modified: ClientDecisionServiceSample/Program.cs

Changes not staged for commit:
(use “git add <file>…” to update what will be committed)
(use “git checkout — <file>…” to discard changes in working directory)

modified: ClientDecisionServiceSample/SingleActionSamples.cs

F:\decision [master +0 ~1 -0 | +0 ~1 -0]> git stash
Saved working directory and index state WIP on master: 71a8dc2 fixed bug with asa due to lack of timestamp and ids on outcome and reward objects
HEAD is now at 71a8dc2 fixed bug with asa due to lack of timestamp and ids on outcome and reward objects

  • Verify and sync with upstream finally: 

F:\decision [master]> git status
On branch master
Your branch is up-to-date with ‘origin/master’.
nothing to commit, working directory clean

F:\decision [master]> git merge upstream/master
Updating 71a8dc2..1175689
Fast-forward
.gitignore | 3 +
ClientDecisionService/App.config | 2 +-
ClientDecisionService/AzureBlobUpdater.cs | 2 +-

  • Un-stash : 

F:\decision [master]> git stash apply
Auto-merging ClientDecisionServiceSample/SingleActionSamples.cs
Auto-merging ClientDecisionServiceSample/Program.cs
On branch master
Your branch is ahead of ‘origin/master’ by 15 commits.
(use “git push” to publish your local commits)
Changes not staged for commit:
(use “git add <file>…” to update what will be committed)
(use “git checkout — <file>…” to discard changes in working directory)

modified: ClientDecisionServiceSample/Program.cs
modified: ClientDecisionServiceSample/SingleActionSamples.cs

  • Check Status: 

F:\decision [master +0 ~2 -0]> git status
On branch master
Your branch is ahead of ‘origin/master’ by 15 commits.
(use “git push” to publish your local commits)
Changes not staged for commit:
(use “git add <file>…” to update what will be committed)
(use “git checkout — <file>…” to discard changes in working directory)

modified: ClientDecisionServiceSample/Program.cs
modified: ClientDecisionServiceSample/SingleActionSamples.cs

no changes added to commit (use “git add” and/or “git commit -a”)

4. Git checkout – For undoing changes

5. Git Commit History

  • To check the list of commits that have gone in
    • git log
  • To view details of last 4 commits
    • git log -p -4
  • To view changes in a file
    • git log -p .\DecisionServiceWebAPI\packages.config

6. Git Commit History

 

References:

  1. http://stackoverflow.com/questions/292357/what-are-the-differences-between-git-pull-and-git-fetch