How to test a WebApi service? - c#

I'm really new to WebApi and I've been reading information about it but I don't know how to start my application.
I already had a project with many WFC services with .Net 3.5. So, I updated my project to 4.5.1. Then I created a controller with the Visual Studio 2012 Wizard. Then, when the controller is created, I see a class as a template with the get, post, put, delete methods. So I place my post method and finally I want to test the service with a HttpClient.
I tried to apply the solution in green from the following forum:
How to post a xml value to web api?
I'm gonna receive a XML string with the structure of a Contract model.
I run my project into Visual Studio Development Server.
But I have troubles with URL to test my service.
I saw many pages where people do something like this http://localhost:port/api/contract. But I don't still know how it works. So how can I do to test my service? What is it my path or url to test my service?

WebApi, like MVC, is all based on the routing. The default route is /api/{controller}/{id} (which could, of course, be altered). This is generally found in the ~/App_Start/WebApiConfig.cs file of a new project, but given you're migrating you don't have it most likely. So, to wire it up you can modify your Application_Start to include:
GlobalConfiguration.Configure(WebApiConfig.Register);
Then, define that class:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
If you created a TestController controller and wanted to make a POST request to the instance running locally, you'd access http://localhost:12345/api/Test/ (with the appropriate verb). 12345 would be the local port that Visual Studio is using to host your service (and can be found by viewing the project's properties, then navigating to the "Web" tab).
Having said that, testing is probably best performed on the the project (without making an external call). There are several posts on the subject, but generally come down to something like the following:
[TestMethod]
public void Should_Return_Single_Product()
{
// Arrange
var repo = new FakeRepository<Widget>();
var controller = new WidgetController(repo);
var expected = repo.Find(1);
// Act
var actual = controller.GetWidget(1) as OkNegotiatedContentResult<Widget>;
// Assert
Assert.IsNotNull(actual);
Assert.AreEqual(expected.Id, actual.Content.Id);
}

Related

Web api versioning method

I have read many links over the internet about web api versioning and every blog post or resource I have found is very clear about how to implement this feature.
However, unfortunately, I have to implement this feature for an API which is already in production and that does not respect any of the solutions I have read until now.
This API has a base address like http://api.server.com and handle more than one resource. These resource all have been routed by ASP.NET attribute routing like {resource}/{id}. For example
POST http://api.server.com/peoples/new
GET http://api.server.com/peoples/5
Actually the web api configuration is very simple like the following
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I have been assigned the task to reenginer this api and would like to create and implement a new versioning scheme that sits side by side to the existing one.
I would like to use the url versioning method in a way that next realease will have the version in the url like
POST http://api.server.com/{version}/peoples
GET http://api.server.com/{version}/peoples/5
and implement a better adherence to restful recommendations in this new version (like removing the verb from the url for example).
How can I obtain this? Could you give some recommendations, examples or link to read which explain how to implement this feature and leave the actual version working?

Exposing a few calls from an existing asp.net-mvc site to other REST clients within an intranet?

I have an existing asp.net-mvc web site and now I need to expose of a few of my calls to external applications that are only used within my site right now. This is all happening within an intranet within my company.
I have read this page which explains Web API versus controller actions as well as this SOF question which seems to have a similar issue but the answers seem a bit outdated. So I am trying to determine given the latest available functionality what is the simplest solution to meet my requirement.
In my case, since I already have the same controller actions used within my current website then WEB API doesn't really make sense but if I google anything around asp.net-mvc authentication or security I only see articles around web API.
Given that, I am trying to figure out best practice for exposing my controller action to another application.
In an ideal world you would convert the app to web api controllers as someone else suggested but to be more pragmatic you can implement an interim solution where you expose only the required calls via extending ApiController
You did not mention which version of MVC your current app is using nor did you mention how your current Controllers return data to the web app.
I will therefore assume you return data via a view model and razor views. eg:
public class ProductsController : Controller
{
public void Index()
{
var view = new ProductsListView();
view.Products = _repository.GetProducts();
return View(view);
}
}
Suppose now you want to expose the products list via a REST-like api?
First check you have web api installed (via nuget)
Install-Package Microsoft.AspNet.WebApi
(again i'm not sure what ver of asp.net you are on so this process may differ between versions)
Now in your public void Application_Start()
GlobalConfiguration.Configure(WebApiConfig.Register);//add this before! line below
RouteConfig.RegisterRoutes(RouteTable.Routes);//this line shld already exist
and in WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I like to create a dedicated folder called ApiControllers and add controllers with the same name; this way you can have controllers with the same names as they are in different namespaces:
namespace YourApp.Web.ApiControllers
{
[AllowAnonymous]
public class ProductsController : ApiController
{
[HttpGet]
public HttpResponseMessage Products()
{
var result = new ProductResult();//you could also use the view class ProductsListView
result.Products = _repository.GetProducts();
return Request.CreateResponse(httpStatusCode, result);
}
}
}
You can then access this via yourapp.com/api/products
nb, try to reduce duplication of code inside controllers - this can be acheived by extracting common parts into service classes.
While I would highly recommend using a web service architecture, such as Web API or ServiceStack, you can expose controller actions.
You'll first want to decorate the actions with the [AllowAnonymous] attribute. Then, in your web.config you'll need to add the following code block to the configuration section for each action you want exposed.
<location path="ControllerNameHere/ActionNameHere">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
As you may have guessed, this becomes very repetitive and annoying, which is why web services would be a great choice.
I had a similar requirement where website 2 needed to call some controller actions from website 1. Since there was no changes in the logic I wanted to avoid the whole rewrite using web API. I created another set of controller and actions that would return Json. The new controller actions would call the original controller actions and then convert the result data to json before returning. The other applications (website 2) would then make http get and post requests to get json data and deserialize it internally. Worked nicely in my case.
I didn't have to put a security layer over the json based actions as they were public, but you might need one to authenticate the requests.
Although webapi is the best way but you don't need to convert your controller/actions to webapi at all.
You could easily achieve what you are after by restricting the controller/actions by IP addresses from your intranet. Just make sure that all intranet sites reside on the same domain other cross domain jquery ajax calls will not work.
Here is an eg. Restrict access to a specific controller by IP address in ASP.NET MVC Beta
An alternative is to use basic authentication and only allow a hardcoded userid/password to access those controller/actions and call via ajax:
beforeSend: function (xhr) {
xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},

Limit a .NET Web API post to same origin

I'm using VS 2013 .NET Web API 2.
I know with .ajax calls you have to enable Cross Origin (CORS), however, how would I limit server side POST requests.
If I have an endpoint called /api/images that accepts posted images in the form of a Base64String, how do I make sure that someone can't submit a POST to that end point from anywhere other than the origin domain (example.com).
Right now I check the Request.Headers.Host and if that's not the origin domain I return a 403 Forbidden Response.
var origin = Request.Headers.Host;
if (origin != "example.com"
return ForbiddenResponse;
I imagine that is easy to fake. Is there another way to do this besides implemented a form of oAuth? Something simple like an API Key that needs to be passed back and forth (or is it possible that could be read via Fiddler)?
What I'm trying to solve is there is a flash object which sends an image to an api end point. I obviously don't want anyone else to be able to send an image to that end point.
Currently you can use CORS support for ASP.NET Web API 2
https://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors
Article Excerpt ------
Enable CORS
Now let's enable CORS in the WebService app. First, add the CORS NuGet package. In Visual Studio, from the Tools menu, select Library Package Manager, then select Package Manager Console. In the Package Manager Console window, type the following command:
Install-Package Microsoft.AspNet.WebApi.Cors
This command installs the latest package and updates all dependencies, including the core Web API libraries. User the -Version flag to target a specific version. The CORS package requires Web API 2.0 or later.
Open the file App_Start/WebApiConfig.cs. Add the following code to the WebApiConfig.Register method.
using System.Web.Http;
namespace WebService
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
Next, add the [EnableCors] attribute to the TestController class:
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
namespace WebService.Controllers
{
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
}
Without going into too much detail you could use some sort of public/private encryption key that gets POST'ed along with the image.
I just did a search and came across this article that might help you with the encryption on the Flash side. The article deals with databases but the info on encryption is in there:
http://help.adobe.com/en_US/as3/dev/WS8AFC5E35-DC79-4082-9AD4-DE1A2B41DAAF.html#WS61068DCE-9499-4d40-82B8-B71CC35D832C
Once you have that squared away you could do the decryption on the API side. They would just need to share a passkey of some sort. on the .NET side refer to this article:
http://blogs.msdn.com/b/shawnfa/archive/2009/03/17/authenticated-symmetric-encryption-in-net.aspx
Hopefully this helps a little bit. Without the use of some sort of authentication method it will be quite difficult to protect your endpoint from spoofed posts.
Also notice that the flash encryption uses AES-CCM so you will have to do the decryption with this method on the .NET side.

Stumped SelfHosting WebApi Services

Please help, I'm trying to self-host a web api.
When the same controller is hosted on a web project, and run on dev, via F5, everything works well.
However now I'm trying to self-host the same, I'm getting 411 and 404. 411, when I use Fiddler to connect, 404 when I'm attempting to connect via another library.
This is the console app that's supposed to host the service:
class Program
{
static int portNumber;
static void Main(string[] args)
{
portNumber = 8089;
var config = new HttpSelfHostConfiguration(
string.Format("http://localhost:{0}", portNumber));
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
using (var server = new HttpSelfHostServer(config))
{
var test = new RetrieveGuidService().Execute(Unit.Instance);
server.OpenAsync().Wait();
Console.ReadLine();
}
}
}
This is what my controller looks like, it doesn't do anything it's just a test.
public class RetrieveGuidServiceController : ApiController
{
public virtual Guid PostExecute(Unit request)
{
IQueryService<Unit,Guid> queryService = new RetrieveGuidService();
return queryService.Execute(request);
}
}
And here's how I'm attempting to access it via fiddler:
The same works when the service is hosted on a web project. I have followed this tutorial almost to the letter: asp.net WebApi self host tutorial which includes running nugget scripts, adding dependencies, etc.
What am I still missing?
The 411 is because you didn't put the Content-Length header. Even if you are not sending content you need to include Content-Length: 0.
Regarding having the Controller in the correct assembly I have had inconsistent behaviour. In some projects it seems to work in other it doesn't. Not sure what I am doing wrong. I have a project here that does both Web Host and Self-Host with all the controllers in a different assembly and it works just fine.
It seems that by default, the services will not look for controllers in assemblies beyond the one hosting the services.
I think it's an omission, unless I'm reading the specs wropng.

Minimum files needed to deploy webAPI server side

So after a great deal of research I'm starting to enhance our service server stack with a webAPI entry point. Based on this thread, and especially the last post by a member of the Digerati board, we are implementing webAPI services as a facade into our WCF application layer. (Our WCF services are just facades into our Application layer where all of the behavior lives)
My question is this. I downloaded MVC 4 and created a new WebAPI project in my service solution. But wow there was a ton of crap that created in my project that I just am not going to need! For example, all of the image files, the home controller, views and models, etc.
So in stripping this down to be just a service project, what are the minimum files I need to build a functional service project? Our intent is to publish both of the service types (WCF and webAPI) side by side in the same server .. each service call doing the same identical service call and returning the specific DTO for the request. So far it looks like App_Start, Controllers, and the Glabal.asax/web.config entries. I definitely don't need Views, Models, or Images!!!
Any input on what others have done to do a pure service deployment would be of great welcome here.
Same problem here. I've found that article from Shawn Kendrot explaining how to create minimal Web API project. It was written for the beta version of Web API but it seems to be still valid.
Create an empty ASP.NET project.
Add a reference to System.Web.Http and System.Web.Http.WebHost (version 4.0.0.0)
Add a Global.asax file
Register a route in the Global.Application_Start. Something like:
protected void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
}
Add a controller
public class SampleController : ApiController
{
public string Get(int id)
{
return "Hello";
}
}
Run the project locally with the URL /api/sample/123 and enjoy the outcome:
FYI. I have found that I have had to reference two more .dlls:
System.Net.Http
Newtonsoft.Json

Categories

Resources