Scott Hanselman

HTTP PUT or DELETE not allowed? Use X-HTTP-Method-Override for your REST Service with ASP.NET Web API

February 5, '14 Comments [20] Posted in ASP.NET Web API
Sponsored By

I got an email today where someone had built a REST(ful/ish) API with ASP.NET Web API that had a customer who was against the idea of using GET, POST, PUT, and DELETE, and insisted that they only use GET and POST.

Sometimes this is because of a browser or client limitaton, sometimes it's a really tense corporate firewall. They wanted to know what they could do.

One thing you can do is to "tunnel" HTTP Methods inside another HTTP Header. Basically you have a header that says "No, seriously, I know I got here via a POST, but use this one instead." You would still POST, but then you'd have "X-HTTP-Method-Override:PUT" as a header.

Here is a PUT in the Postman REST client:

image

So that's:

PUT /api/Person/4 HTTP/1.1
Host: localhost:10320
Content-Type: application/json
Cache-Control: no-cache

And here's the same PUT, except as a POST plus an X-HTTP-Method-Override header.

image

Raw, that's like this:

POST /api/Person/4 HTTP/1.1
Host: localhost:10320
Content-Type: application/json
X-HTTP-Method-Override: PUT
Cache-Control: no-cache

Now, how do you get ASP.NET Web API to respect this new way to route things? You may have a Web API Controller like this:

public IEnumerable<Person> Get() { }

// GET api/person/5
public Person Get(int id) { }

// POST api/person
public void Post([FromBody]Person value) { }

// PUT api/person/5
public void Put(int id, [FromBody]Person value) { }

// DELETE api/person/5
public void Delete(int id) { }

And you likely don't want to change it. Make a MethodOverrideHandler like this one. You can add the code yourself, get it from a NuGet package, or use one from the WebAPIContrib project. It's up to you.

public class MethodOverrideHandler : DelegatingHandler
{
readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
const string _header = "X-HTTP-Method-Override";

protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for HTTP POST with the X-HTTP-Method-Override header.
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
return base.SendAsync(request, cancellationToken);
}
}

You see it checks if it's a post, looks for the extra header, then changes the request's Method property after the message has been received, but before it's been sent through the pipeline. It'll show up on the right method just as if a PUT had been sent, because from its perspective, a PUT was sent.

You need to register this new MethodOverrideHandler in your WebApiConfig like this, just by adding to the MessageHandlers collection, next to the rest of the configuration and routing code.

public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new MethodOverrideHandler());

//OTHER REGULAR STUFF HERE

// Web API routes
config.MapHttpAttributeRoutes();

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

On the client side, you can keep sending a post with your .ajax call in jQuery, for example, just make sure the override header in there.

$.ajax({
url: "http://localhost:10320/api/Person/4",
type: "POST",
data: JSON.stringify(whatever),
headers: {
"Content-Type": "application/json",
"X-HTTP-Method-Override": "PUT" },
})

That's the general idea, enjoy!


Sponsor: Big Thanks to Aspose for sponsoring the blog this week! Aspose.Total for .NET has all the APIs you need to create, manipulate and convert Microsoft Office documents and a host of other file formats in your applications. Curious? Start a free trial today.

About Scott

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

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Building Web Apps with ASP.NET Jump Start - 8 Hours of FREE Training Videos

February 28, '13 Comments [41] Posted in ASP.NET | ASP.NET MVC | ASP.NET Web API | Screencasts | SignalR | Speaking
Sponsored By
image

Last week Jon Galloway, Damian Edwards and myself (with a raspy throat) were up in Redmond at the Microsoft Campus filming at Microsoft Virtual Academy.

They've got a whole studio there so we spent the whole day presenting LIVE. There were several thousand folks watching live and interacting with

Very special thanks to Brady Gaster and ASP.NET community members Scott Koon, Peter Mourfield, and Rob Chartier who were furiously handling questions in the chats! Your volunteerism and dedication to the community is deeply appreciated! Let's give them a hand, eh?

Jon worked very hard to put together a great day of content based on the successful Web Camps classes we've given all over the world. We took all this and worked to update it with all the new improvements in the ASP.NET and Web Tools 2012.2 release last week so it's very up to date.

Building Web Apps with ASP.NET Jump Start: (01) What's New in ASP.NET 4.5

Building Web Apps with ASP.NET Jump Start: (01) What's New in ASP.NET 4.5

This module will review what's new in ASP.NET 4.5. It will provide an overview of strongly typed data controls and model binding in web forms, friendly URLs, page inspector, Visual Studio Web Editor features and much more.

 

Building Web Apps with ASP.NET Jump Start: (02) Building and Deploying Websites with ASP.NET MVC 4Building Web Apps with ASP.NET Jump Start: (02) Building and Deploying Websites with ASP.NET MVC 4

In this session the instructors go over ASP.NET MVC 4 and provide several demos on creating a new site; adding a model, controller and view, to using entity framework code first. Lastly they demo how to deploy to Windows Azure Web Sites.

 

Building Web Apps with ASP.NET Jump Start: (03) Creating HTML5 Applications with jQueryBuilding Web Apps with ASP.NET Jump Start: (03) Creating HTML5 Applications with jQuery

This module introduces you to the new standards of HTML5 and provides a demo of how powerful it is. Additionally you will see how it works with ASP.NET MVC 4, jQuery overview, Visual Studio Web Tools, Web Essentials and SPLA Template.

 

Building Web Apps with ASP.NET Jump Start: (04) Building a Service Layer with ASP.NET Web APIBuilding Web Apps with ASP.NET Jump Start: (04) Building a Service Layer with ASP.NET Web API

Have you always want to know how to build a service layer with ASP.NET Web API? This segment shows how ASP.NET Web API fits in, and how to consume Web API from jQuery and Windows 8.

 

Building Web Apps with ASP.NET Jump Start: (05) Leveraging Your ASP.NET Development Skills to Build Office Apps Building Web Apps with ASP.NET Jump Start: (05) Leveraging Your ASP.NET Development Skills to Build Office Apps

Get ready to see several Demos leveraging ASP.NET skills to build apps for Office specifically using HTML 5+ jQuery and ASP.NET Web API. This module will also go into further details regarding apps for Office and how they work. Using jQuery inside Office is freaky and cool.

 

Building Web Apps with ASP.NET Jump Start: (06) Building and Leveraging Social Services in ASP.NET Building Web Apps with ASP.NET Jump Start: (06) Building and Leveraging Social Services in ASP.NET

In this session you will see how to using social authentication with ASP.NET as well as an overview of the new Facebook application template.

 

Building Web Apps with ASP.NET Jump Start: (07) Building for the Mobile Web Building Web Apps with ASP.NET Jump Start: (07) Building for the Mobile Web

This module will provide and overview of adaptive rendering in ASP.NET 4.5 and ASP.NET MVC 4. This is especially important since mobile is fast becoming the primary way people browse the web. We'll also cover jQuery Mobile.

 

Building Web Apps with ASP.NET Jump Start: (08) Real-time Communication with SignalR Building Web Apps with ASP.NET Jump Start: (08) Real-time Communication with SignalR

In this segment the instructors go over SignalR, and an incredibly simple real-time web for .NET. It will also provide an overview for real-time hit counter, what SignalR is and how to build a chat application, a multi-player game and load balancing SignalR.

 

Building Web Apps with ASP.NET Jump Start: (09) Taking Advantage of Windows Azure Services Building Web Apps with ASP.NET Jump Start: (09) Taking Advantage of Windows Azure Services

And where would we be if we could not scale it all up or down. This flexibility can be provided with Windows Azure. Here you will see how Windows Azure fits in with mobile services, virtual machines while managing caching and storage.

 

I hope you enjoy the day! Here's a complete course outline with jumps to specific spots:

Building Web Apps with ASP.NET Jump Start

If you’d like more information, including links to a lot of the sample code, see Jon’s wrap-up post.

Related Links

About Scott

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

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Released: ASP.NET and Web Tools 2012.2 in Context

February 18, '13 Comments [87] Posted in ASP.NET | ASP.NET MVC | ASP.NET Web API | VS2012
Sponsored By

One ASP.NETLast year the ASP.NET team started talking about something we're calling "One ASP.NET." I showed some mockups of our ideas last summer at the aspConf Keynote that you can watch online.

We also announced then that we would add new features to ASP.NET as out of band releases (OOB) without breaking existing functionality. This means that developers don't have to wait for the next version of Visual Studio for great web development features today. We're aiming to add to ASP.NET and Web Tools every 6 months.

For those that don't want to wait, Mads and the team also started a feature playground called Web Essentials. This is an extension to Visual Studio that updates all the time with ideas and brainstorms about how VS can be an even better editor for the web. As features "graduate" from Web Essentials, they move into ASP.NET and Web Tools proper. A bunch of features graduate with today's release.

Today we announced ASP.NET and Web Tools 2012.2. You can use the Web Platform Installer to get ASP.NET and Web Tools 2012.2 now.

Get it with the Online Installer:

Get ASP.NET and Web Tools 2012.2 with Web Platform Installer

OR use the Offline Installers:

1. Get the ASP.NET 2012.2 pieces then get one of these

2. Web Tools 2012.2 for any regular Visual Studio 2012 or  Web Tools 2012.2 for Visual Studio Web Express 

Here's some highlights:

Editors

Syntax Highlighting for client side templating languages within the HTML editor like:

  • CoffeeScript
  • Mustache
  • Handlebars
  • JsRender

Other editors get new features as well:

  • Syntax Highlighting, intellisense and validation for LESS files.
  • Intellisense for Knockout.js bindings!
  • CSS Auto Sync - type into the CSS editor while the site running and get live updates in Page Inspector
  • Everyone's favorite "Paste JSON as Class." Copy some JSON into the clipboard, paste and get either C# or VB classes for your JSON to serialize into.

Browsers

Mobile Emulator support adds extensibility hooks so that third-party emulators and unusual browsers can be installed as a VSIX. The installed emulators will show up in the F5 dropdown, so that developers can preview their websites on a variety of devices. Read more about this feature in my entry on the new BrowserStack integration with Visual Studio.

Packages

With today’s release, all of the ASP.NET templates have updated versions of jQuery, jQuery UI, jQuery Validation, Modernizr, Knockout, and other open source NuGet packages. Your existing projects won't update unless you update them explicitly.

ASP.NET

  • OData support in ASP.NET Web API
  • SignalR included out of the box and fully supported
  • Web Forms now supports Friendly URLs (no more .aspx extension)
  • Web Forms supports device (mobile) specific pages, so product.aspx can also have product.mobile.aspx.
  • Updated Single Page Application template
  • MVC Facebook Application Template
  • Web Sites get the same publishing tools as Web Projects

These are just the highlights. But let me call out one specific feature that gets us closer to one of the main goals for One ASP.NET which is what I call a more level playing field.

Community Project Templates

One of the most significant "under the hood" changes is the ability to add a project template via a VSIX.

We'll be seeing an update to the Visual Studio Gallery soon that will make it so you can upload your own VSIX files (Visual Studio Extensions) that can be installed (and easily updated) into the ASP.NET MVC File New Project dialog with one click.

It's important to know that we're only halfway there. This is likely not what the final unified One ASP.NET dialog will end up looking like, but it's a start as it's a good place to open up for new templates.

Phrased differently, project templates should be as easy to share as NuGet packages. That's a goal.

Another goal is to be able to take an example project that looks the way you want, with the NuGet packages setup as you like them, then "Save As | Project Template" then publish the resulting template/VSIX to the gallery. That means projects like NancyFX, or FubuMvc or whatever you can think of can live next to out of the box templates.

Here's the initial documentation on how you can create VSIXs of project templates, get in this dialog and make it easy to spread your vision of a great web app. We are working to make this process fewer steps and unify things, but this works great now with VS2012.2 so you can get started today. Stay tuned for more on this.

In the near future we'd like to see the community sharing project templates that look the way the community wants them to look, living side by side with templates from Microsoft.

The fully populated ASP.NET MVC 4 New Project dialog has many new templates

As start, we're announcing four Single Page Application (SPA) templates you can install now. Please note that these community templates could be anything, the VSIX hooks are wide open, it's just that the first few happen to be SPA templates.

And, a clever play on words from John Papa (because what do you get in a SPA?)

  • HotTowel - a more complex template that includes knockout, bootstrap, sammy, toastr, q, momentjs, breeze and puts them all together into one SPA example.

Note how nice the HTML editor looks when working on an Ember project, for example. We've got syntax highlighting, HTML5 Intellisense and coloring in our Mustache templates.

Mustache template syntax highlighting

Remember, you'll need the 2012.2 release to see these new templates, so use Web Platform Installer to get ASP.NET and Web Tools 2012.2 now. And, if you want check out our future playground features like Zen Coding, CoffeeScript and lots more, also pick up Web Essentials. Note that Web Essentials is a small extension and if it causes you any trouble you can just disable it.

Should you fear this release?

ASP.NET and Web Tools 2012.2 doesn't change any GAC'ed (Global Assembly Cache) files. It won't mess up your install of ASP.NET or change any existing projects. It's changes are either tooling within Visual Studio, or additions and improvements via local NuGet packages.

Go get it. ASP.NET and Web Tools 2012.2

About Scott

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

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Integrating Mozilla Persona with ASP.NET

January 24, '13 Comments [13] Posted in ASP.NET | ASP.NET MVC | ASP.NET Web API | Open Source
Sponsored By

imageASP.NET and Web Tools 2012.2 is coming soon, but one of the features of ASP.NET that you can use TODAY is support for Google, Twitter, Microsoft and Facebook logins out of the box with ASP.NET templates. I show how OAuth in ASP.NET works in this 5 minute video. We are also continuing to look at ways to make membership easier in coming versions of ASP.NET like including things like this out of the box.

Mozilla has a new identity system called Mozilla Persona that uses browserid technology to let users log in to your site without creating a custom login or username.

I wanted to see how Persona would work in ASP.NET and hacked up a prototype (with some sanity checking from my buddy Hao Kung). There's some comments and some TODOs, but it's a decent proof of concept.

First, I read the Mozilla Persona Developer docs and got their fancy button CSS, then added it all to the ExternalLoginsListPartial view.

The Magic Persona button is very blue

The ProviderName check is there just because all the buttons look the same except the Persona one. A better way, perhaps, would be partial views for each button, or a custom helper.

@foreach (AuthenticationClientData p in Model)
{
if(p.AuthenticationClient.ProviderName == "Persona") //ya, ya, I know.
{
if (!Request.IsAuthenticated) {
<p><a href="#" class="persona-button" id="personasignin"><span>Sign in with your Email</span></a></p>
}
<!-- The CSS for this is in persona-buttons.css and is bundled in in BundleConfig.cs -->
}else{
<button type="submit" name="provider" value="@p.AuthenticationClient.ProviderName" title="Log in using your @p.DisplayName account">@p.DisplayName</button>
}
}

After the login dialog, an AJAX call to do the login locally posts data to my new PersonaController. except it doesn't POST its assert as JSON, but rather as a simple (standard) POST value. That is, just "assertion: longvalue."

function onAssertion(assertion) {
if (assertion) {
$.ajax({ /* <-- This example uses jQuery, but you can use whatever you'd like */
type: 'POST',
url: '/api/persona/login', // This is a URL on your website.
data: { assertion: assertion, },
success: function (res, status, xhr) { window.location.reload(); },
error: function (res, status, xhr) { alert("login failure" + res); }
});
}
else {
alert('Error while performing Browser ID authentication!');
}
}

ASP.NET Web API doesn't grab simple POSTs cleanly by default, preferring more formal payloads. No worries, Rick Strahl solved this problem with this clever SimplePostVariableParameterBinding attribute which allows me to just have string assertion in my method.

Armed with this useful attribute (thanks Rick!) my PersonaController login is then basically:

  • Get the assertion we were given from Persona on the client side
  • Load up a payload with that assertion so we can POST it back to Persona from the Server Side.
  • Cool? We're in, make a local UserProfile if we need to, otherwise use the existing one.
  • Set the FormsAuth cookie, we're good.

Here is the work:

[SimplePostVariableParameterBinding]
public class PersonaController : ApiController
{
// POST api/persona
[HttpPost][ActionName("login")]
public async Task<HttpResponseMessage> Login(string assertion) {
if (assertion == null) {
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
var cookies = Request.Headers.GetCookies();
string token = cookies[0]["__RequestVerificationToken"].Value;
//TODO What is the right thing to do with this?

using (var client = new HttpClient()) {
var content = new FormUrlEncodedContent(
new Dictionary<string, string> {
{ "assertion", assertion },
{ "audience", HttpContext.Current.Request.Url.Host }
//TODO: Can I get this without digging in HttpContext.Current?
}
);
var result = await client.PostAsync("https://verifier.login.persona.org/verify", content);
var stringresult = await result.Content.ReadAsStringAsync();
dynamic jsonresult = JsonConvert.DeserializeObject<dynamic>(stringresult);
if (jsonresult.status == "okay") {
string email = jsonresult.email;

string userName = null;
if (User.Identity.IsAuthenticated) {
userName = User.Identity.Name;
}
else {
userName = OAuthWebSecurity.GetUserName("Persona", email);
if (userName == null) {
userName = email; // TODO: prompt for custom user name?
using (UsersContext db = new UsersContext()) {
//TODO: Should likely be ToLowerInvariant
UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == userName.ToLower());
// Check if user already exists
if (user == null) {
// Insert name into the profile table
db.UserProfiles.Add(new UserProfile { UserName = userName });
db.SaveChanges();
}
}
}
}

OAuthWebSecurity.CreateOrUpdateAccount("Persona", email, userName);

FormsAuthentication.SetAuthCookie(email, false);
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
return new HttpResponseMessage(HttpStatusCode.Forbidden);
}

[HttpPost][ActionName("logout")]
public void Logout() {
WebSecurity.Logout();
}
}

You click Sign in and get the Persona login dialog:

Animation of the Persona login

At this point, you're logged into the site with a real UserProfile, and things with ASP.NET Membership work as always. You can add more external logins (Twitter, Google, etc) or even add a local login after the fact.

You are logged in!

As I said, this isn't ready to go, but feel free to poke around, do pull requests, fork it, or comment on how my code sucks (in a kind and constructive way, because that's how we do things here.)

About Scott

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

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

When in doubt, turn on Tracing

January 1, '13 Comments [12] Posted in ASP.NET | ASP.NET Web API
Sponsored By

One of my favorite posts that I've done is "The Internet is not a black box. Look inside."

I really want to encourage folks to look inside "black boxes" - or more accurately, what they perceive as black boxes - in order to solve their issues.

I got a great question from blog reader Eddie F. He also knows I don't like to waste keystrokes so he mentioned that I could blog the result if I answered his question. Hat tip to Eddie.

He says:

I have a case with an Entity Framework 5.0 entity that refuses to "PUT" to my ASP.NET WebApi controller (all .NET 4.5 RTM) if I add the [Required] data annotation to a property on my entity class which I find really bizarre.

So Eddie has an entity with the [Required] attribute on a property. When he PUTS (not POSTS) he gets an error:

var response = client.PutAsJsonAsync("/api/MagicPants/Update", entry).Result; 
//HERE IS THE POINT OF FAILURE when the [Required] attribute
// is added to the EF poco type PortfolioEntry.

If he removes [Required] it works. If he uses any other DataAnnotation like RangeValidation, it also works.

Eddie points out that he's Googled (with Bing) all over and found nothing. He has asked lots of friends and StackOverflow before asking me. Very thoughtful.

I replied with this to get more info.

What happens underneath? You're describing an interaction with a black box without pushing under....what does tracing say? What does Fiddler say?
http://blogs.msdn.com/b/henrikn/archive/2012/08/15/asp-net-web-api-released-and-a-preview-of-what-s-next.aspx

Eddie replied:

That question, along with your provided hyperlink to Henrik’s blog (bookmark… check) allowed me to discover web api tracing.  Genius!  I feel like I’ve been riding in the car, but now I feel like I’ve taken the wheel.  Thank you!

As an ASP.NET guy I take this to mean that Tracing isn't easily discoverable in the product. However, once you know it exists (through all of ASP.NET) things get interesting. You have to know to ask about Tracing (and hence, Google) before you can unlock its power. Most products have tracing or logging or "turn diagnostics up to 11."

Eddie said:

Tracing was very clear about the problem:

iisexpress.exe Error: 0 : Operation=FormatterParameterBinding.ExecuteBindingAsync, 
Exception=System.InvalidOperationException:
Property 'OrderOfMagnitude' on type 'TFSPortfolio.Models.PortfolioEntry' is invalid.
Value-typed properties marked as [Required] must also be marked with
[DataMember(IsRequired=true)] to be recognized as required.
Consider attributing the declaring type with [DataContract]
and the property with [DataMember(IsRequired=true)].

at System.Web.Http.Validation.Validators.ErrorModelValidator.Validate(ModelMetadata metadata, Object container)
...
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)

I had the DataMember attribute on the property but not the IsRequired=True

So I add the attribute and bingo!

Even better, Eddie knows about T4 and is code-generating his Entities so he adds:

I’ll have to make another minor tweak to the T4 template for this attribute to fix this globally… gotta love T4 for this job.

A great result via a clarifying question about a question. When in doubt, turn on tracing!

About Scott

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

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Page 1 of 2 in the ASP.NET Web API category Next Page

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