Scott Hanselman

One ASP.NET - Making JSON Web APIs with ASP.NET MVC 4 Beta and ASP.NET Web API

February 25, 2012 Comment on this post [47] Posted in ASP.NET | Javascript | Open Source | Web Services
Sponsored By

ASP.NET MVC 4 Beta came out last week. It's got lots of new features as well as some surprises that move us closer to the "One ASP.NET" idea. I talked about this a little in this week's MSDN Flash email newsletter (you can subscribe to MSDN Flash here; it's reasonably high signal, low noise). Here's part of what I said:

Don't think of ASP.NET as an island. It's a citizen of the larger community. More and more of ASP.NET is open source, and we push hard every day to stay open and be open. We want to make ASP.NET more pluggable, more open, more fun. We've got big things planned - some that will surprise you. I hope you'll join the conversation and the community.

Here's some of the stuff that's been improved in MVC 4.

New Features in the Beta

  • ASP.NET Web API
  • Refreshed and modernized default project templates
  • New mobile project template
  • Many new features to support mobile apps
  • Recipes to customize code generation
  • Enhanced support for asynchronous methods
  • Read the full feature list in the release notes

You may have heard me talking about LEGO in the past, and showing how you can fit things together better with NuGet. I've mentioned One ASP.NET in the context of the new features in Web Forms as well. Here's a diagram I've shown internally a few times. We'll keep adding more information about how these fit together and what you can build with them on http://asp.net/vnext.

All the parts of ASP.NET, all the subsystems are all part of the larger ASP.NET community

In fact, in the interest of focusing on One ASP.NET, the "WCF Web API" is now ASP.NET Web API and it comes with ASP.NET MVC now. Even though it ships with MVC 4 Beta today, don't let that take away from the One ASP.NET vision. You can use Web API in ASP.NET Web Forms no problem. That's kind of the point. ;)

Why do you want a Web API?

If your app - your business's data model - has an API, then suddenly your Web API is opened up to native apps, iPhone apps, Windows 8 apps, whatever, apps. It's Web Services. Remember those?

I can use XML or JSON or something else with my API. JSON is nice for mobile apps with slow connections, for example. You can call an API from jQuery and better utilize the client's machine and browser. You can make a Gmail type single page, or a hybrid; it's up to you.

How it all fits into One ASP.NET

The idea behind One ASP.NET is that I want folks to be able to make apps that have real-time components with SignalR, clean, simple APIs with Web API, all in one pages with KnockoutJS, pages with MVC, Web Forms or Web Pages, as well as existing ASP.NET systems like OData, ASMX, and more. I want open source projects like JSON.NET, KnockoutJS, SignalR, Backbone, MongoDB, Scaffolding, NHIbernate, Ninject (and the list goes on) to all play in the same ASP.NET LEGO sandbox. We'll put all these subcomponents on NuGet and they'll live alongside community components and you'll be able to build ASP.NET applications starting from some base template and add just the pieces you want. We are getting there. I want folks to use the parts they want, and swap out the parts they don't. Everything should work together. I've always said I want to open source everything we can as fast as Microsoft can take it, and I'll keep pushing if it kills me my boss.

NotTwitter

Lemme make a NotTwitter app real quick. Here's a quick model:

public class NotATweet
{
public int ID { get; set; }
public string Username { get; set; }
public string Text { get; set; }
public DateTime Published { get; set; }
}

I'll use the default scaffolding to get the UI, but then I'll install the MvcScaffolding extra NuGet package and scaffold it using a Repository pattern.

PS>Scaffold -ModelType NotATweet -DbContext NotTwitterContext -Scaffolder Repository -Force 

Then I'll scaffold a controller that uses this Repo (you can do this from the UI or from the NuGet package console):

Scaffold -Controller NotATwitter -ModelType NotATweet -DbContext NotTwitterContext -Scaffolder MvcScaffolding.Controller -Repository

And here's the resulting Scaffolded UI.

It's Not Twitter

The controller for my pages is standard fare. Now I'll add one via Add Controller to make an API for my NotTwitter application.

I'll change my route to make /api go to my app's API controller;

routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{id}",
defaults: new { controller = "NotATwitterAPI", id = RouteParameter.Optional }
);

Here's my Web API controller code. A few things to notice. I'm talking to the same IRepository that the page controller uses. I'm returning HTTP Status Codes that are appropriate for each response. See how after the Create (where I POST a JSON representation of NotATweet) that I return HttpStatusCode.Created 201 and set the header's location to include the location of the new resource?

public class NotATwitterAPIController : ApiController
{
private readonly INotATweetRepository notatweetRepository;
    public NotATwitterAPIController(INotATweetRepository notatweetRepository)
{
this.notatweetRepository = notatweetRepository;
}

// GET /api/notatwitterapi
public IQueryable<NotATweet> Get()
{
return notatweetRepository.All;
}

// GET /api/notatwitterapi/5
public NotATweet Get(int id)
{
var notatweet = notatweetRepository.Find(id);
if (notatweet == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return notatweet;
}

// POST /api/notatwitterapi
public HttpResponseMessage<NotATweet> Post(NotATweet value)
{
if (ModelState.IsValid)
{
notatweetRepository.InsertOrUpdate(value);
notatweetRepository.Save();

//Created!
var response = new HttpResponseMessage<NotATweet>(value, HttpStatusCode.Created);

//Let them know where the new NotATweet is
string uri = Url.Route(null, new { id = value.ID });
response.Headers.Location = new Uri(Request.RequestUri, uri);

return response;

}
throw new HttpResponseException(HttpStatusCode.BadRequest);
}

// PUT /api/notatwitterapi/5
public HttpResponseMessage Put(int id, NotATweet value)
{
if (ModelState.IsValid)
{
notatweetRepository.InsertOrUpdate(value);
notatweetRepository.Save();
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
throw new HttpResponseException(HttpStatusCode.BadRequest);
}

// DELETE /api/notatwitterapi/5
public void Delete(int id)
{
var notatweet = notatweetRepository.Find(id);
if (notatweet == null)
throw new HttpResponseException(HttpStatusCode.NotFound);

notatweetRepository.Delete(id);
}
}

Then I'll hit /api with Fiddler. Notice how JSON popped out the other end?

ASP.NET Web API in Fiddler

I'll change the accept header to Accept: application/xml and xml pops out. You can plug in your own and make Web API spit out iCal or whatever you like. You can make media formatters or even plug in others for the defaults. For example, here's a JSON.NET Formatter for Web API.

GET returns a 200 and an XML list of NotTweets

Now can we make NotTweets? You can use tools like the JSON Formatter to handcraft JSON for testing. Now I'll POST a Json serialized NotTweet:

POST gets back an HTTP 201

Notice that the result is an HTTP 201 Created. If I then GET /api, I can see it's there:

Standard /api GET

I can also affect things with the URL and query strings like this GET /api?$orderby=Username HTTP/1.1 so I can so query composition without totally buying into OData-style URLs if I don't want to.

Web API with an orderby querystring

As I mentioned, I can use XML or JSON or something else with my API. JSON is good for mobile apps with slow connections, for example. You can call this API from jQuery and better utilize the client's machine and browser.

There's also the "calling" side of this, which is HttpClient. You can call out to other APIs like Twitter and authenticate using OAuth. Other people might call your API from the client side using jQuery and Javascript or from the server side using HttpClient.

Web API has many more possibilities than this example. Spend some time on Henrik's blog (he helped invent HTTP! Listen to him on his episode of the Hanselminutes Podcast)

We've got a new section up on the ASP.NET site http://asp.net/web-api with a lot of info. Here's some resources for easily adding an API to your app. You can even self-host your own Web API without IIS in a service or other application!

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
February 25, 2012 4:35
Hi Scott. Any idea how DTO->view model object mapping would fit into this whole flow? For example: I want public IQueryable<NotATweet> Get() to actually return NotATweetViewModel. I could do this manually (via automapper/some custom function) but then I lose the OData filtering provided by the framework and be enumerate the whole IQueryable<>. I've been trying all day to do this via an action filter but I haven't had much success. Ideally I'd love to let the framework do its thing, then have an OnActionExecuted filter handle the transformation.

I've been asking around in the official wep api forums but haven't had much luck. Any insight would be appreciated.. thanks! = )
February 25, 2012 5:52
Can I get ASP.NET Web API through NuGet?
Rob
February 25, 2012 7:05
Annoyingly, I couldn't find a super simple web pages-like JSON API alternative, the closest was using WebClientFactory WCF .svc's, which have their own set of problems. MVC is a nice architecture, but it's crazily overweight for introducing when you are still playing around with code-first TDD against the database, especially when I'm not even serving HTML in the end! Of course, that's a pretty edge case, and I could just write an IHttpHandler subclass, but it seems like a violation of the LEGO-brick concept that JSON APIs depend on the HTML generation machinery at all.
February 25, 2012 7:10
Chris - I'll ask.

Rob - yes, links under Related Links for NuGet stuff

Simon - Can you be more specific? I've done JSON.net and IHttpHandler, Kayak and Owin, using a single .cshtml web page to return JSON, or just return json() from a controller. All are very lightweight. Returning Json() doesn't invoke any HTML building or page generation stuff (views).
February 25, 2012 7:24
So then of course, I see that the related links talk about how you can use Web API without MVC extremely simply! Though the http://www.asp.net/web-api should really include that Henrik post, it's example for using WebAPI without MVC is crazily complicated, showing off far to many unrelated features.
February 25, 2012 8:45
Thanks Scott. That was a very gentle RTFM. Forehead meet palm. :D
Rob
February 25, 2012 9:05
Simon - good point! I'll update the site to make it clearer that it is lightweight.

Rob - We are all friends here! ;)
February 25, 2012 9:12
Can we hope for something like Kayak in the ASP.NET lego box? We want to do web services between medical devices in a closed network. A lightweight, open source web server from Microsoft would be really nice.
February 25, 2012 9:17
Could we download your example, please?
Thank you,
February 25, 2012 12:09
Does Web API offer any performance/resource usage improvements compared to serving JSON from an MVC controller?
February 25, 2012 12:13
Bango - Sure. However, have you looked at the link about on how you can host Web API inside any service or application? Does that help?

Ignat - I'll put something on bitbucket but have you tried any of the samples above?
February 25, 2012 14:13
And you could not tell us this on Techdays because? :P

Did miss you there..
February 25, 2012 15:13
Hi Scott, any idea if the OAuth authentication scheme will sooner or later be integrated into the framework?
It would be the ultimate web api extension :)

Thanks again for the article.
February 25, 2012 18:59
Can't wait to do some more MVC4-WebAPIng...

Authentication mode="Forms" works great with [Authorize(Roles = "Myrole")]

But how do my NonHuman client logon ?

Great article
February 25, 2012 19:44
Hi Scott,

I have read that the PUT and DELETE actions should be idempotent methods, meaning that multiple identical requests should have the same effect as a single request.

Looking at your code does this is not true for the delete method. At least the second call results in an exception thrown. If the entity does not exist even the first call would result in an exception.

Apart from that I am rather keen on the Web API.
Thanks for a great post!

Regards
Andreas Kroll
February 25, 2012 19:45
Installing the Nugets "aspnetwepapi" on my MVC3 app works nicely too :-) LEGO-yes I known - just had to unhook that mvc4 thought..
February 25, 2012 20:34
Scott: yes , we use that already. But we also need to render web pages. The scenario is this: a device measures patient's vital signs. Other devices pull that data via Web API. A nurse walks around with a tablet, where we render that same data in a browser.

We did a prototype using Web API, SignalR and MVC3 and it all worked, but the lack of a lightweight server is a problem. So I'm now running Louis DeJardin's firefly with Nancy and will probably stay with that.

MVC4 looks great. But there is still that big unwieldy lego piece -the server- that steers me away from the entire stack.
Having to deal with http.sys , netsh, urlacl, running things as admin. There has to be a better way.


February 25, 2012 20:43
this is awesome ... RESTful API
much similar to Rails 3 default restful routing
with xml and json format.

February 26, 2012 1:35
Just when you thought you knew it all!! boom something fantastic and exciting on the Microsoft stack to learn I can already see this keeping me awake at night I think 4.5 is an exciting release great work go team go
Thanks
February 26, 2012 1:52
Hi,

This is really cool stuff.

The only doubt I have about this is in comparison to *.ws is the descriptional part. With web services it's quite easy to implement the service and send the wsdl to someone else (including the comments) and they will be able to use it.

Is there some sort of discovery method/extension for Web API?

BTW: The OpenID sign in doesn't work in Chrome
February 26, 2012 13:27
@Andreas

You are correct that DELETE is an Idempotent operation, but idempotency relates to how the server state is affected. In this case once the resource has been removed and a DELETE is sent you get a 404, which is completely valid as the server state is not effected.

Technically PUT should really compare the state being updated to the state of the resource and if it has not changed then it is no-op. However in this case it is just overwriting itself with the same values so from the client perspective nothing has really change.

Cheers
Glenn
February 27, 2012 2:56
Hi Scott,

In response to my first comment above, I think I've found a simple & valid work-around that doesn't break the IQueryable<> chain:

public IQueryable<NotATWeetViewModel> Get( ) { return _repo.ListAll( ).Select( x=> AutoMapper.Mapper.Map( x, new NotATweetViewModel() ) ); }

It still doesn't offload the mapping to an ActionFilter as I would like, but the end result is all that matters.
February 27, 2012 3:45
Banko,

You can host Nancy on the WebAPI using the OWIN adapter for WebAPI. It's not quite an Open Source web server, but it does make the applications a little more portable since they don't depend on IIS.

More info here: http://owin.org/

Information on the GATE adapter for OWIN and WebAPI.
http://whereslou.com/2012/02/20/gate-adds-owin-support-for-the-new-asp-net-web-api-beta

February 27, 2012 5:59
Thanks, Scott (Koon)! I didn't know there was an OWIN adapter for the Web API. I'll try that.

February 27, 2012 13:47
OH MY GOD, YES. I loved the WCF Web Api (sic) when it was first trialled on Codeplex. It makes so much sense. However, the URL templating, the ServiceRoute<T> paradigm, it all seemed to fit the ASP.NET (MVC in particular) world so much more.

Brilliant work. Can't wait to see these "surprises" too.
February 27, 2012 14:23
Big hello from down-under Scott!

I can't find any info on how to use the Web Api from Web Pages (without MVC). Is it not possible? If yes, any docs?
February 27, 2012 17:42
FYI, I threw together a quick tutorial for making requests using the HttpClient class that's included in the latest bits. It's a rough cut, but it gets it done. Consuming your own ASP.NET Web API REST Service
I will try and add the POST and PUT examples soon, and I welcome any feedback!
February 27, 2012 21:48
Scott,

I am interested in the One ASP.NET concept as it relates to Web API and SignalR. I don't know much about SignalR other that what I read from your post in August. My question is, how are these two services meant to be utilized in one ASP.NET application? What type of requests would each service handle?
February 28, 2012 22:40
Glenn - Thanks for the review. I'll update the code a little.

Michael - I will do a post on WCF, Web API and SignalR together, OK?

Nuri - I'll see if I can do a post. You can find all docs (so far) at http://www.asp.net/web-api
February 29, 2012 6:12
Hmmm, Scott.

I'm still waiting to see the iOS and WP7 version of NerdDinner. It seems to be missing from the must-have list....

February 29, 2012 13:59
Is the WebAPI trying to move the services towards REST? All this looks like WCF REST services, except we are using controller in an MVC application.

So do we need to have 2 controllers? 1 extending from Controller base and another from ApiController base?
March 01, 2012 1:46
how about a vb.net example?
jim
March 01, 2012 20:43
Great article, Scott.

Is it true that you're not adding support for OData $select queries for the RTM?
Seems kind of a shame if you aren't.
March 03, 2012 6:42
It's pretty exciting for me too, when working for the new version for Employee Info Starter Kit, for demonstrating cool stuffs available in ASP.NET MVC & Web API 4.0. Guys you can have a early look at here.
March 12, 2012 5:30
Great example. Just had to add this to get it working...


namespace NotTwitter.Controllers
{
public class NotATwitterAPIController : ApiController
{
public NotATwitterAPIController() : this(new NotATweetRepository())
{
}
March 19, 2012 10:26
Can the authorize attribute work well with certain clients that will not support cookies authentication? Does it switch to header based authentications when needed? I would love a tutorial or more explanation on using authentication over web api.
March 20, 2012 3:17
Hey Scott, loving the MVC4 beta so far. Any word if we are going to get full OData support in the official release of MVC 4? Specifically the inlinecount option. Not having this really kills the ability to do any kind of paging (efficiently).

Thanks...again awesome work on MVC 4, it's really great!
July 13, 2012 14:29
Scott
I worked on MVC Razor v.1 for Webapplication.
I agree WEB-API is the best REST Complaince service tech available now.

But in application scenarios, one controller will be dealing with multiple views and View1 may call a method GetAdminUsers() and View2 may call GetCommonUsers().

In this scenario, how we can handle with WEB-API.

To summarize, how we can use custom action method names in WEB-API . . .
August 24, 2012 23:28
Likning.
If i use entity framework, using à stored procedure, to gather data; lets say that i get the objekt from class that have id like below
Class myclass
{
Public int id;
}
I want to insert à link to the resppnse like below:
<myclass>
<id>10000</<id>
<link hef="bablablabla" rel="self">
<myclass>

how easy is that??

Thaks in advance
September 01, 2012 15:22
All the examples for web api that I have seen post a single object to the api. Is it possible to post a collection of objects (IQueryable<NotATweet>) to the api and have the nice automatic json to .net conversion happen?
September 12, 2012 5:51
Really though how are we supposed to trust Microsoft ever again as a developer after them abandoning Silverlight and WPF? They are all HTML5 and Javascript now, which are great things but now they are just another open source Javascrip vendor (and not so open)....and the other vendors do a better job....why bother really? Do you really think we are going to jump on the Metro bandwagon and have the rug pulled out from us again? I am dumb but I am not stupid. I remember going to PDC and listening to Doug Purdy yelling about how Oslo was the greatest thing since sliced bread. I could go on and on....Microsoft has lost me and I am sure many others. Off to learn python....
October 11, 2012 22:52
What scaffold command did you use to make the apicontroller use your repository? Can you post that or explain how you generated that apicontroller please?
October 11, 2012 23:16
Josh - From the right click menu, add a new Controller and chose Web API Controller.
October 11, 2012 23:50
I installed the Oct 8 version and I don't see that as an option? WebAPI controller using repository?
I do see other options that use Repository for normal controlller only?
March 01, 2013 1:45
Is there a way to get Web API to return .cshtml views?
June 01, 2013 17:39
This is awesome!! really helpful for me. Thanks for sharing with us. Following links also helped me to complete my task.

http://www.mindstick.com/Articles/f50bdd96-7941-495c-aa53-169d9711a096/?Select%20Insert%20Update%20and%20Delete%20using%20Stored%20Procedure%20in%20ASP%20NET%20MVC4

http://www.c-sharpcorner.com/UploadFile/krishnasarala/select-insert-update-and-delete-with-Asp-Net-mvc/
July 04, 2013 2:33
Scott,

Two questions:

1) Is there a web page somewhere that shows all the options for the Scaffold command line options?
2) Is there a way for the scaffold to look at the entity framework for keys and default values without having to modify the entity framework generated code?

Thanks,
Michael

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.