I am using Fiddler to debug my MVC application and see all the HTTP requests.
The application is running on http://localhost:51234/mvc
As anybody who has tried to use Fiddler for a site hosted on localhost knows there is an issue - windows won't forward localhost traffic through the proxy if you hit this link directly. You can work around this in several ways, such as my prefered way of using the URL http://ipv4.fiddler:51234/aboutus/contact. This works great.
The problem was I started doing AJAX using :
<% using (Html.BeginForm()) { %>
If you view the source generated it has actually generated this :
<form
action="http://localhost:51234/aboutus/contact"
method="post"
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), {
insertionMode:
Sys.Mvc.InsertionMode.replace,
onFailure:
Function.createDelegate(this,
submitComments_failure), onSuccess:
Function.createDelegate(this,
submitComments_success) });">
Oops!
It generated localhost instead of ipv4.fiddler:51234. So of course when I run the AJAX query Fiddler doesn't see it.
In theory using the machine name should work, but the WebDev.WebServer won't respond if you try to hit directly the machine name http://win-538lf:51234/aboutus/contact
[Fiddler] Connection to
win-538lf failed. Exception
Text: No connection could be made
because the target machine actively
refused it
fe80::81fc:8f0f:457a:27df%12:51234
Is there a workaround for this?
is it possible to configure WebDev.WebServer to respond to the machine name? Or am I going to have to create a virtual directory or fake host ? I'd prefer not to do that, but i guess its not a big deal.
So it turns out that if you use this overload :
using (Ajax.BeginForm(new AjaxOptions()
you get this code generated (the code that 'breaks'):
<form action="http://localhost:51234/aboutus/contact" method="post"
but if you do this and include the action name:
using (Ajax.BeginForm("Contact", new AjaxOptions()
you get this code generated :
<form action="Contact" method="post"
So i'm fine with that for now, but would welcome any other solutions.
Have you tried the Firebug extension for Firefox? It can show the Ajax request and response. I've used it with ASP.NET Ajax. Not sure about MVC Ajax.
You could write a HTTPModule which uses a response filter in order to manipulate the HTML output replacing all "localhost:51234" strings.
The HttpResponse class has a very useful property:
public Stream Filter {get; set;}
MSDN provides a helpful description of this property:
"Gets or sets a wrapping filter object
used to modify the HTTP entity body
before transmission."
Here is a nice article which gives some background how you could do this: Implementing an IIS Application Filter Using .NET HttpModules and Response Filtering (page 3)
As described in the object browser,
the Filter gets or sets a wrapping
filter object used to modify the HTTP
entity body before transmission’. This
is exactly what we need to do in order
to make modifications to the HTML
output of the HttpHandler. The Filter
property is declared as type
System.IO.Stream. In order to assign
our own class to this filter property
we need to define our class as
inheriting from System.IO.Stream:
public class PageFilter : System.IO.Stream
We now have a Stream class,
PageFilter, which can be assigned to
the Response.Filter property. By
attaching PageFilter to the
Response.Filter property, PageFilter
will be notified at critical times as
data is written to the Response
buffer. The most significant event of
course is the Write operation. When
this method is called, you’ll have the
opportunity to modify data as it’s
being written to the Response buffer.
(I combine this with 'Response.Buffer
= true' so that my PageFilter receives the complete response stream in a
single method invocation.):
public override void Write(byte[] buffer, int offset, int count)
In the HttpModule, at the start of the request (I do it in OnBeginRequest) simply attach your HTTP response filter by assigning a new instance to Response.Filter:
httpCtx.Response.Filter =
new PageFilter(httpCtx.Response.Filter)
This other article shows a full working example implementation:
http://aspnetresources.com/articles/HttpFilters.aspx
I hope this helps!
Related
I've been getting the same old error every time I test a new URL from my browser's address bar when I'm returning Json (using the built-in MVC JsonResult helper):
This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.
Rather than grunt in acknowledgement and fire up Fiddler to do a post request, this time, I'm wondering exactly what it is that a GET request exposes that a POST request doesn't?
in your return use the following:
return this.Json("you result", JsonRequestBehavior.AllowGet);
Say your website has a GetUser web method:
http://www.example.com/User/GetUser/32
which returns a JSON response:
{ "Name": "John Doe" }
If this method accepts only POST requests, then the content will only be returned to the browser if an AJAX request is made to http://www.example.com/User/GetUser/32 using the POST method. Note that unless you have implemented CORS, the browser will protect the data from other domains making this request to yours.
However, if you allowed GET requests then as well as making an AJAX request similar to the above with GET instead of POST, a malicious user could include your JSON in the context of their own site by using a script tag in the HTML. e.g. on www.evil.com:
<script src="http://www.example.com/User/GetUser/32"></script>
This JavaScript should be useless to www.evil.com because there should be no way of reading the object returned by your web method. However, due to bugs in old versions of browsers (e.g. Firefox 3), it is possible for JavaScript prototype objects to be redefined and make it possible for www.evil.com to read your data returned by your method. This is known as JSON Hijacking.
See this post for some methods of preventing this. However, it is not a known problem with the later versions of modern browsers (Firefox, Chrome, IE).
By default, the ASP.NET MVC framework does not allow you to respond to
a GET request with a JSON payload as there is a chance a malicious user can gain access to the payload through a process known as JSON Hijacking. You do not want to return sensitive information using JSON in a GET request.
If you need to send JSON in response to a GET, and aren't exposing sensitive data, you can explicitly allow the behavior by passing JsonRequestBehavior.AllowGet as a second parameter to the Json
method.
Such as
[HttpGet] //No need to decorate, as by default it will be GET
public JsonResult GetMyData(){
var myResultDataObject = buildMyData(); // build, but keep controller thin
// delegating buildMyData to builder/Query Builder using CQRS makes easy :)
return Json(myResultDataObject, JsonRequestBehavior.AllowGet);
}
Here is an interesting article from Phil Haack JSON Hijacking about why not to use Json with GET method
When we want to return a json object to client from MVC application, we should explicit specify JsonRequestBehavior.AllowGet when returning an object. As a result, I return json data as below to overcome the issue:
return Json(yourObjectData, JsonRequestBehavior.AllowGet);
You must be use JsonRequestBehavior.AllowGet for Json Response like this :
return Json(YourObject, JsonRequestBehavior.AllowGet);
return Json("Success", JsonRequestBehavior.AllowGet)
We have a website that uses Orchard CMS and we've written a "RedirectFilter" to do permanent redirects on legacy URLs (aliases that don't match the AutoroutePart pattern for the relevant Content Item).
The filter implements IActionFilter and inherits FilterProvider. It works fine and when it does a redirect it calls the following method in OnActionExecuting:
filterContext.HttpContext.Response.RedirectPermanent(targetPath, true);
According to the documentation the second parameter suggests that a ThreadAbortException will be thrown to abort the current request. However, the request is still processed for the legacy URL, I know this because the Part Drivers still execute for both the legacy and new URLs.
How can I abort the request from the filter without Orchard continuing to execute it?
Just worked this out. Need to use this instead:
filterContext.Result = new RedirectResult(targetPath, true);
I'm guessing you can't call RedirectPermenant inside a filter.
Can you give me any general advice on how to debug ASP.NET MVC Binding?
When everything works as expected, ASP.NET MVC is great. But if something does not, like something doesn't bind for some unknown reason, I find it hard to trace down the problem and find myself spending hours tracking down a seemingly simple problem.
Let's imagine you land in a controller method like this:
[HttpPost]
public ActionResult ShipmentDetails(Order order)
{
//do stuff
}
Let's further imagine that the Order class looks like this:
public class Order
{
public decimal Total {get; set;}
public Customer Customer {get; set;}
}
public class Customer
{
public string Name {get; set;}
public string Phone {get; set;}
}
What are good places to start when Order in the controller method is not bound correctly? What are good places to start when only parts of the Order are bound correctly?
Although #russ's answer is useful and will sometimes be necessary, both options seem a little low level when the main question is more about the big picture. Thus, I'd recommend Glimpse.
From its about page:
… Glimpse allows you to debug your web site or web service right in the browser. Glimpse allows you to "Glimpse" into what's going on in your web server. In other words what Firebug is to debugging your client side code, Glimpse is to debugging your server within the client.
And since you've specifically asked about data binding, you'll want to look at the binding tab documentation. You'll be able to see, again from the docs:
Ordinal: Order in which the MVC Model Binding infrastructure attempted to bind the available data
Model Binder: Model Binder that was used in a given scenario
Property/Parameter: Name of the thing that the Binder was trying to bind
Type: Type of the thing that the Binder was trying to bind
Attempted Value Providers: Providers that the Binder attempted to use to get a given value (and whether it was successful)
Attempted Value: The actual value that the provider has to work with (post type conversation, etc.)
Culture: The culture that was used to parse the raw value
Raw Value: The raw value that the provider has to work with (pre type conversation, etc.)
See the quick start. Briefly:
Install the glimpse.mvc3 package
Go to http://yourhost/yourapp/Glimpse.axd and "turn it on."
Click on the glimpse icon on the bottom right of any view in your app for details.
As Darin has suggested, start with inspecting what is being sent from the client to the server using something like Firebug, Fiddler, or other web debugging proxy tool.
Failing that, you might want to step through the source code to see what's happening during binding.
Two ways that I can recommend doing this are
Include the System.Web.Mvc source code project in your application and reference this. This is good for learning but probably not recommended for a commerical application.
Download the symbols for System.Web.Mvc from the Microsoft Symbol servers, change your settings to be able to debug framework source code and set a break point appropriately to step through.
In my case looking at the ModelState property in the controller method provided the answers why the modelbinding was failing.
A good place to start is download and install FireBug and see what gets posted from the client to the server. Then you will see what's missing, incorrect, ... Blog posts such as Model Binding to a List are good reads as well to get acquainted with the proper syntax that the default model binder uses.
From Visual Studio side:
Set a breakpoint on entry to your endpoint.
Open the Immediate via the Debug menu option.
Type in ModelState.Keys.ToList()
This will show the binding errors by name/key.
Better yet type in ModelState.Values.ToList()...
Put a breakpoint in your controller-method and make a watch for Request.Params to see what is actually coming in to the controller in terms och parameters.
Since upgrading from mvc 2 beta 2 to rc I'm having trouble with an ajax submission in Internet Explorer. Upon carrying out a jquery form post, the function returns a url to a controller action. This worked fine with the controller action picking up it was a ajaxrequest and then piping back a partial view to update the page. This still works fine in Firefox, however in Internet Explorer the final call to the controller action now comes from cache and returns therefore returns a full view rather than partial.
I've tried setting the outputcache to 0 with no success and I've also tried the nocache actionfilter as described here Disable browser cache for entire ASP.NET website with no luck. The only way I can stop IE from pulling from cache is to physically delete the cached version.
Anyone have any ideas (apologies if this isn't very clear, tricky one to explain!)?
For some reason, IE is really aggressive about caching AJAX GETs. So if you are fetching that via AJAX, the behavior is not surprising to me. Also not surprising is that using output cache attribute didn't fix the problem, because it is IE, rather than the server, which is doing the caching. What you need to do is to tell IE not to cache the request, by setting the appropriate headers in the HTTP. Here is how we do it:
[CacheControl(HttpCacheability.NoCache), HttpGet]
public JsonResult DoStuff()
{
//...
}
public class CacheControlAttribute : ActionFilterAttribute
{
public CacheControlAttribute(HttpCacheability cacheability)
{
this._cacheability = cacheability;
}
private HttpCacheability _cacheability;
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
cache.SetCacheability(_cacheability);
}
}
My 2 cents to Craig's great solution -
If you're using a user control and rendering it using an "RenderAction"
<% Html.RenderAction("UserList", "User"); %>
And this page invokes it via GET as well as POST then don't mention the request method in the attribute declaration.
[CacheControl(HttpCacheability.NoCache)]
For example, I've a search Grid and a search panel on top of it. I've made my Grid a user-control so that I can invoke the sort & paging via AJAX (GET) still it is also invoked when I press the "search" button (POST) so I need it for both.
In ASP.NET MVC the convention is that a controller action method should return an ActionResult (or a type derived from ActionResult).
However, you can write a public method that returns pretty much anything and if that method is called (from a browser) the framework will package the return value up as a ContentResult and the browser receives a page of plain text.
This is all very interesting - but would you ever want to do this?
When you want to render something directly from your controller? e.g. using Response.Write(...); (or using other Response methods).
Not returning anything from an action method is essentially not responding to the client's HTTP request with a response.
An empty request might make sense in some cases (HTTP status being enough of a reply), but all web application patterns return something more than this (including, if I understand it correctly, REST: the new state of the entity).