Move ASP.NET WebApi 2.0 controller to separate application - c#

We have a WebApi 2.0 application with several controllers, one of which is used to relay data. Due to issues with scalability, we want to move that particular controller out to a separate process so that we can scale it separately from the rest of the application, possibly on a different server altogether. We don't want to break compatibility though, and until we can get all of the clients updated, we will still have requests being made to the old endpoint that controller sat on. What is the simplest way to redirect those requests (it must work with GET/POST/DELETE) to the new location? Does this have to be done within IIS, or is there a way to modify the route? So far we've tried simply returning a redirect response within the old controller, but this doesn't work properly for POST:
public async Task<HttpResponseMessage> Post()
{
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri("http://new/api/endpoint");
return response;
Even if it did, we have some library components that use WebClient with auto-redirect turned off, and those would need to be refactored, which is not ideal. Is there a guaranteed solution?

A redirect is nothing more than an HTTP response with a particular status code and some extra information. If your client application isn't going to follow a redirect than that's not an option for solving your problem.
You could have your Post() method act as a proxy for the other web service. As an example, if your first API is at example.com/Site1 and your second API is at example.com/Site2 then you could have your client make a request to Site1 while Site1 internally makes a request to Site2.

Related

How to properly make a call to a Web API

In the ASP .NET website they have an example of how to call a Web API from a .NET Client.
They have this method to make a call which creates a new Product:
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync("api/products", product);
response.EnsureSuccessStatusCode();
// Return the URI of the created resource.
return response.Headers.Location;
}
This is like the usual way to make any call to any API in any language or framework, but I see a lot of problems in this line:
HttpResponseMessage response = await client.PostAsJsonAsync("api/products", product);
If the "path" parameter is a string, there is no way to detect possible errors in compilation time. Besides, if the API changes and we have a lot of calls, there is no way to rebuild the calls quickly.
Is there a better way to build the call to avoid this kind of problems? I mean, like we do with Web Services, for instance.
Like Nkosi mentioned, that is how it is designed. However you could create a class with the API URI's and use those instead of literals
public class ApiUris
{
public const string Products = "api/products";
public const string Services = "api/services";
public const string Orders = "api/orders";
/* ... */
}
That way you can easily change the path if your webapi changes.
Even Web Service and WCF service does not gurantee build fail if the server changes the URL or type and/or structure of the parameter. You come to know about the changes only when you call the service and it breaks.
In case of calling Web APIs surely there is no way you can figure out that the URL or the paramemeter is incorrect until you call the API.
At the same time, Web API are not built to be changed frequently. If they are not reliable no one would use them. So if you are using an API you can be sure that they will not change their URL or stop supporting certain input parameters overnight making their consumer applications like yours break. They surely woudn't want to be sued by their customers.
Any API would change gradually and with well advanced notice to their customers so that they get time to change their implementation to support new version of API.
So you can rely on the service which you are using and puting values related to it (such as URLs) in the config file would be good enough. Or you can choose to put API Urls in database so that when it changes you just need to update entry in the database and changes will be effective immediately.
Just extending upon Adam's solution you can get a List of your routes using
System.Web.Routing.RouteTable.Routes.ToList();
Then getting the path depends on the concrete implementation of the RouteBase abstract class.

Allow cross site post request on specific ASP.NET Core controller

I am using a complex template for my new ASP.NET Core application. Now I wanted to create a new controller which receives a POST request from another external server. That didn't work. I tried a lot until I found out that there is a mechanism set up which only allows POST request to access my controller which have a certain header (X-XSRF-TOKEN). This is done to prevent a Cross-Site-Request-Forgery attack.
However one specific controller should allow such requests, because this controller is not used from the webpage visitors browser. Is there a way to annotate the controller or any other way to allow this exception?
I finally found the answer and it is indeed possible by using an annotation. Just annotate your controller or action with [IgnoreAntiforgeryTokenAttribute] and the whole XSRF mechanism won't bother your controller any more.
Note that even if you don't intend to use that controller action from a browser, if it can be accessed via http, it may easily be susceptible to CSRF. An attacker may still for example create a rogue webpage, which if visited by one of your users, makes the user send a request to that action. If session management is cookie-based or equivalent and the action changes server state, it would still be an exploitable vulnerability.
So while you can turn of CSRF protection, you need to consider consequences carefully.

Making restful calls to asp.net web api

I am currently following this tutorial to create a simple REST service using Web Api. Note this is my first time doing something like this and I am just trying to learn more.
http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web-api-that-supports-crud-operations
I have followed all the instructions and have it successfully running on my localhost. I understand that in this tutorial the URI for all my GET requests look something like:
localhostapi/products/id
And I understand that, and how to perform simple GET requests in the URI and see it actually occuring using my developer tools in my browser.
Now my question is... How do I make POST/DELETE/PUT requests and actually see what they are doing? The guide wasn't too clear, do I pass in parameters into the URI? Does the URI change when I want anything but a GET request? This text here seems to explain it but I do not understand:
The method takes a parameter of type Product. In Web API, parameters with complex types are deserialized from the request body. Therefore, we expect the client to send a serialized representation of a product object, in either XML or JSON format.
It's quite easy to make POST, PUT, DELETE requests. You just need to install Fiddler at http://www.telerik.com/download/fiddler
Next, install and run it. Go to the Composer tab on the right hand side. Next, put your local host URL, and the request method, and other data like the screenshot below
You can write unit tests, like
[TestMethod]
public void GetAllProducts_ShouldReturnAllProducts()
{
var testProducts = GetTestProducts();
var controller = new SimpleProductController(testProducts);
var result = controller.GetAllProducts() as List<Product>;
Assert.AreEqual(testProducts.Count, result.Count);
}
This link also This one may help.
more:
How to call ASP .NET MVC WebAPI 2 method properly
Sending C# object to webapi controller
You can set a breakpoint on your controller methods that handle the post/delete/put.
Same thing in your browser at the point where you call the post/delete/put (presumably in a jquery request)
You can also unit test your controller methods:
http://www.asp.net/mvc/tutorials/older-versions/unit-testing/creating-unit-tests-for-asp-net-mvc-applications-cs

Authorization through a ASP.NET Web API in Orchard CMS

Creating an ASP.NET Web API module in Orchard CMS is simple and straightforward. The following link explains how to do it and it works just fine. http://www.sebastienros.com/web-api-makes-it-in-orchard
However, the GET requests does not work when the WebAPI is running under Orchard and you use the [Authorize] attribute at the same time.
[Authorize]
public IEnumerable<string> Get()
{
return _moduleManager.GetUsers().Select(n => n.UserName);
}
When I call this from the client
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials = new NetworkCredential("user", "password");
HttpClient client = new HttpClient(handler);
var response = await client.GetAsync("http://localhost:30321/OrchardLocal/api/MyWebAPIModule/Users");
Console.WriteLine(response);
the response variable returns to me the "Not found" HTML page from Orchard. Without the [Authorize], it returns a list of users.
Does Orchard have something already built-in to match the credentials with a registered user in Orchard? Or is there steps missing in the process?
This blog post may be a helpful resource for a deeper understand ASP.NET's Authorize attribute. It might help to look in the web.config file to see what the authentication mode is set to.
I think the problem is that if you are making a call in code, you need to pass any cookies in the request.
A user is authenticated against the website by the use of the aspnetAuth (or FedAuth) cookie, which is provided by the browser. So if you called /OrchardLocal/api/MyWebAPIModule/Users from the browser you would expect this to work (you should see this happen in fiddler by looking at the headers/cookies).
However if you make a call in code you need to pass cookies/auth. header yourself. The call you have does not have any of this, thus it fails (you should see the absence of the cookie in fiddler for this request).
I'm not sure why you would call the api in this way from within your own module. Presumably the API controller calls a service that does the actual workload. You could call this service directly from your Driver/Action, still safe in the knowledge that your business logic is behind the service interface.

How do you handle an Async Response from a Web Service

I was given the task of creating a web based client for a web service.
I began building it out in c# | .net 4.0 | MVC3 (i can use 4.5 if necessary)
Sounded like a piece of cake until I found out that some of their responses would be asynchronous. This is the flow ... you call a method and they return a response of ack or nack letting you know if your request was valid. Upon an ack response you should expect an async response with the data you requested, which will be sent to a callback url that you provide in your request.
Here are my questions:
If I'm building a web app and debugging on localhost:{portnum} how can I give them a callback url.
If I have already received a response (ack/nack) and my function finishes firing isn't my connection to the client then over ? How would I then get the data back to the client? My only thought is maybe using something like signalR, but that seems crazy for a customer buy flow.
Do I have to treat their response like a webhook? Build something separate that just listens and has no knowledge of the initial request. Just save the data to a db and then have the initial request while loop until there is a record for the unique id sent from the webhook.... oye vey
This really has my brain hurting :-/
Any help would be greatly appreciated. Articles, best practices, anything.
Thanks in advance.
If you create your service reference, it will generate a *ServiceMethod*Completed delegate. Register an event handler on it to process your data.
Use the ServiceMethod_Async() method to call the service.
The way I perceived your question is as follows, though please correct me if I'm wrong about this:
1) You send a request to their endpoint with parameters filled with your data. In addition, you send a:
callback url that you provide in your request. (quoted from your question)
2) They (hopefully) send an ack for your valid request
3) They eventually send the completed data to your callback url (which you specified).
If this is the flow, it's not all that uncommon especially if the operations on their side may take long periods of time. So let's say that you have some method, we'll call it HandleResponse(data). If you had originally intended to do this synchronously, which rarely happens in the web world, you would presumably have called HandleResponse( http-webservice-call-tothem );
Instead, since it is they who are initiating the call to HandleResponse, you need to set a route in your web app like /myapp/givemebackmydata/{data} and hook that to HandleResponse. Then, you specify the callbackurl to them as /myapp/givemebackmydata/{data}. Keep in mind without more information I can't say if they will send it as the body of a POST request to your handler or if they will string replace a portion of the url with the actual data, in which case you'd need to substitute {data} in your callback url with whatever placeholder they stipulate in their docs. Do they have docs? If they don't, none of this will help all that much.
Lastly, to get the data back on the client you will likely want some sort of polling loop in your web client, preferably via AJAX. This would run on a setInterval and periodically hit some page on your server that keeps state for whether or not their webservice has called your callback url yet. This is the gnarlier part because you will need to provide state for each request, since multiple people will presumably be waiting for a callback and each callback url hit will map to one of the waiting clients. A GUID may be good for this.
Interesting question, by the way.

Categories

Resources