While working with the Kendo UI Grid for ASP.NET MVC I am finding some frustrating behavior that I can't seem to understand or find any information on. I have a grid which makes a kendoGrid.saveChanges() request to the server which has some server side validation. If the server-side validation fails, it returns the following result:
Response.StatusCode = HTTP_BAD_CLIENT_REQUEST; // const int 400
return PartialView("Error/BadRequest");
The partial view just has some basic HTML for displaying the error information to the user, and the grid's datasource error callback does the following:
function errorCallback(e) {
// Handles explicit Ajax and Kendo DataSource error callbacks
var content = e.responseText || e.xhr.responseText;
// Wrapper around a kendo.ui.Window to display content
Core.Alert.raiseAlert(content);
}
When I run my project in debug mode, or publish the Release version of the project to my local machine the e.xhr.responseText value is populated correctly i.e. it contains the partial view's HTML message. However, as soon as I move this to the production server the e.xhr.responseText simply contains the value "Bad Request" which is also the HTTP status code I am currently using. I've tried using other status codes but the result is the same (error name is used as the responseText).
The reason I find this to be so odd is that I am doing something similar in another project for an internal application at our company and this works perfectly fine. They are running on the same versions and tools of both Kendo and ASP.NET.
Can anyone point me in the direct of tools or documentation, Kendo or AJAX, which explain why the response text is not using my partial view result or how I can map the partial view result I am sending to the xhr.responseText property?
Edit: With trying different error codes, I found that certain status codes such 405 (Not Allowed) resulted in the IIS server error html being returned. So now I'm really stumped, why is it that some status codes simply return a name of the request, while others return templated HTML for that error code when I am specifying the return value and view to return?
Credit for findings and solutions goes to this post.
After doing some digging, I figured out that the issue came down to IIS overriding the content (and therefore partial view) being sent when I used the error HTTP status codes.
The solution is to add an <httpErrors> tag to the system.webServer in the web.config. I found that the following was sufficient to get my partial views to reach the client.
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
Related
I'm not sure of the best way to accomplish my goal. Looking for insight. I'm familiar with WebAPI services consumed through WPF and Silverlight but this is my first run at ASP and MVC.
I am building a site to verify contents of a shipment against an electronic manifest (EDI 856). I have a page that displays the shipping data and I need the users to scan each item barcode in the container. I would then like to pass that barcode to a service, verify the item belongs in that shipment and then update the page to show as much.
My plan was to have a single text box into which the user could scan/type the barcode and then submit that data to a WebAPI service which would verify the information and then probably use SignalR to send a message back to the page and update a grid with the item data.
If this is a decent way to go, I'm just not quite sure how to use ajax to call the WebAPI endpoint and provide the data I need.
I would advise against using SignalR in this situtation. What you need, judging from your description, is the most basic use case of submitting an ajax request and receiving a response.
You are not designing a system where you need the server to initiate communication with the browser or anything like that, where sockets (and SignalR as an abstraction over sockets with fallbacks to less suitable protocols) is a huge overkill.
Don't worry, your use case is rather simple.
It's a little out of scope to describe how to setup a WebApi project, how to configure routing, action names, etc. Simple google searches will surely provide ample quality tutorials on getting started.
I'll just try to explain what the general idea is, with some code samples, to get you thinking in the right direction.
You need to create an ApiController.
The simplest version of that Controller will probably look something like this:
public class ShipmentVerificationController : ApiController
{
//this is the response object you will be sending back to the client website
public class VerificationResult
{
public bool Valid;
}
public VerificationResult GetIsItemValid(string BarCode)
{
bool itemIsValid;
// Implement checks against the BarCode string here
itemIsValid = true;
return new VerificationResult { Valid = itemIsValid };
}
}
Note that the inner class represents the response you will be sending back. It should be properly filled out with additional info if needed and probably put into a separate .cs file in the "Models" folder or where ever you see fit.
I have declared it inside the controller for demonstration purposes only
Once you have a WebApi service deployed, it's really easy to send it data from your website and receive the feedback.
To simplify Ajax requests, jQuery is often used.
Once the user inputs the barcode into a textbox, you can hook up an event to check for return key being pressed (most barcode scanners send the return key command after they input the barcode data) and then write something along the lines of:
var barcode = $("#input-field").val();
$.getJSON( "<url_to_your_webapi_service>/api/ShipmentVerification/GetIsItemValid/" + barcode, function( data ) {
if (data.Valid) {
// great, highlight the item as valid
}
else {
//better indicate an error with the scanned item
}
});
Please note that for simplicity I have not included any error handling, url parameter encoding, and most importantly, zero authorization.
Authorization is very important if you deploy the web service to the open web but still do not want anyone to be able to call it.
You will have to research these topics yourself, but I hope I have presented you the core concepts and logic behind a simple service such as this, so you have a base to start with.
If you come up with specific problems and questions post a new question.
I actually found a more simple way to do this. I nixed the idea of using a WebAPI endpoint and just went with a normal controller. I used ajax to prevent the page from refreshing with the new view, since that view is actually just json data with my return values in it.
Have a problem on production server. On local and test servers this problem is not reproduced.
.NET 4.5, Sitecore 7.2.
Several user controls have the following directive:
<%# OutputCache VaryByParam="*" Duration="300" VaryByCustom="VaryByUrl" %>
Note: corresponding sitecore sublayouts have caching is turned off.
Method in Global.asax:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
switch (custom.ToLower())
{
case "varybyurl":
return context.Request.Url.DnsSafeHost + context.Request.RawUrl + OutputCacheKey;
}
return base.GetVaryByCustomString(context, custom);
}
Previously caching was working normally. But since recent times, it was broken suddenly (but only on live server). Its behavior:
Page #1 with user control (that have mentioned directive) is loaded with some information (e.g. "Text A").
Then I am opening another page #2 with the same control but with another data (which should have "Text B"), but "Text A" is shown on this control on this page.
Only after 300 seconds, after refreshing the page #2, it shows "Text B".
I was trying to add the logging into GetVaryByCustomString and no logs was received on live server, so it means that method was not called.
Maybe someone has any idea why it works in such way?
Thank you!
Cause of problem is found!
Global.asax file was absent on live server.
It was not delivered during last build for some reason.
Current issue could be closed :)
I am trying to move the content of a textbox on the from StudentRegistration to the form MyProfile by following a tutorial on YouTube. However when I try to reference the StudentRegitration Page in my code, I get the error that the type or namespace cannot be found.
In the tutorial I can see that in their code they have a namespace, however my website does not. Could anyone tell me what to do in order to be able to reference StudentRegistration without getting an error?
I should have stated that I have a website not a web app. I have found that websites do not have a default namespace. How would I go about accessing the StudentRegistration without referencing a namespace?
public partial class MyProfile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (PreviousPage != null)
{
StudentRegistration LastPage = (StudentRegistration)Context.Handler;
lblEmail.Text = StudentRegistration.STextBoxEm;
}
}
}
Rather than answer your question directly, I'd like to point out another issue with your code that will probably prevent it from working. You should refer to the documentation on the PreviousPage property at: http://msdn.microsoft.com/en-us/library/system.web.ui.page.previouspage%28v=vs.110%29.aspx
It does NOT work like this:
user visits /StudentRegistration.aspx
user does stuff
user submits the form on /StudentRegistration.aspx
server redirects the user to /MyProfile.aspx
MyProfile class knows that PreviousPage = the class from /StudentRegistration.aspx
Instead, the description from the msdn reference page linked above stipulates that the PreviousPage property only works on this scenario:
user visits /StudentRegistration.aspx
user does some stuff
user submits form on /StudentRegistration.aspx
server transfers request to the MyProfile class
this does not mean that the url has changed to /MyProfile.aspx for the user, this means that the server is going to treat the current request to /StudentRegistration.aspx as if it were actually a request to /MyProfile.aspx
the user ends up seeing the result of what would normally be /MyProfile.aspx on /StudentRegistration.aspx
Now, your code may actually want that, but the fact that you have:
if (PreviousPage != null)
{
StudentRegistration LastPage = (StudentRegistration)Context.Handler;
// this should be
// StudentRegistration LastPage = (StudentRegistration)PreviousPage;
}
makes me think that you have misinterpreted the somewhat misleadingly named PreviousPage property. For a sample of how to persist state across multiple page loads in .NET, I would recommend reading up on SessionState. It has a somewhat complicated name, but does more of what you would want in this scenario:
http://msdn.microsoft.com/en-us/library/ms178581%28v=vs.100%29.aspx
An added bonus is that you do not need to reference one class from another, so you fix your current bug later on. Additionally, even if you did resolve your potential namespace error, the issue that I outlined earlier will cause the value of the text field to be blank if your code is working as I suspect.
You are sending data from a source to a target - e.g. StudentRegistration -> MyProfile
You have options because at the end of the day, it is HTTP. Aside from "persistence" (Session), and the tutorial you are following, a "simpler" way is to use ButtonPostBackUrl.
All it means is that you are POSTing data to the target page. The target page (MyProfile) will have to validate and parse the posted data (Request.Form). This way you don't have to manage things like Session state.
I have tried everything, even uninstalling asp.net mvc3, and I can't get HandleError global filter working.
I have set up the HandleError filter in the Global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Also I have CustomErrors enabled (it does not matter if i set defaultRedirect="Error" or not, I think that is in the docs because is needed for older versions of mvc):
<customErrors mode="On" />
Trying to navigate through the page until the error gets raised, wether you do from localhost or using the hostname, inside the development server or IIS 7.5, it always redirects to a standard status 500 page, instead of my custom Error.cshtml view that I have created in Shared. Here is Error view code:
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Oooops";
}
<h2>Ooops Something really bad happened!</h2>
Also I have noted that if I create a new ASP.NET MVC3 project and then select "Internet Application" template, and just enabling customErrors in that project, then the HandleError filter starts working just fine, however using the empty MVC3 template does not.
I want to clarify, that indeed I can see the error view being processing when debugging, however the browser always display Error 500 page.
To fix this all you need to do is edit your Error.cshtml page and make sure that you have set the Layout property correctly. In an Empty MVC 3 Application this is set to NULL, which causes the HTTP 500 internal server error.
I fixed this issue by simply adding:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
I ran into this same issue. I found this post: 500 Internal Server Error in ASP.NET MVC and tried unchecking "Friendly Http Errors" and my HandleErrors attribute started working as expected in IE 8 with IE 7 compatibility mode checked (and started working like it does in Chrome by default). I don't think this is a valid solution for a deployed app, but perhaps there's a way to extend the HandleError attribute so that it redirects to an "Error" controller instead of just the default Error view.
UPDATE: This post shows that when an HTTP Status 500 is returned, IE handles it awkwardly. A way to get around it, is to set the Status to 200, then everything seems to work OK (even in IE).
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
//https://stackoverflow.com/questions/5137627/mvc-handleerror-returns-error-500-and-view-error-page
//https://stackoverflow.com/questions/183316/asp-net-mvc-handleerror
filterContext.HttpContext.Response.StatusCode = 200;
}
}
Well this is hilarous, finally found the answer, this machine has Internet Explorer 9 beta installed and is a difference in behavior when handling the status 500 that the HandleError attribute sets before showing the Error view.
I have tried with other browsers and is working fine:
What I cannot undestarnd now is why the "Internet Appication" template was working though.
Anyone knows where I can post the bug? Should it go to the asp.net mvc team or IE 9 team? How do I contact them?
Found the issue - the error page - make sure you put some dummy content - to make the content size atleast 1KB.
Here are the contents of Error.cshtml
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h2>
Sorry, an error occurred while processing your request. #DateTime.Now
</h2>
<div>
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
</div>
</body>
</html>
Here are the steps I've used and which worked for me:
Create a new ASP.NET MVC 3 project using the Empty template
Add a new controller called HomeController with the following contents (you don't need any view => we are throwing an exception anyway):
public class HomeController : Controller
{
public ActionResult Index()
{
throw new Exception("error");
}
}
Turn on custom errors on web.config by adding the following section:
<customErrors mode="On">
</customErrors>
Run the site and the ~/Views/Shared/Error.cshtml view which was generated by the template will be shown.
I think I found a way around this. Replace your Error.cshtml and _Layout.cshtml with the ones generated from the Internet or Intranet templates.
Monitoring my global exception logs this error seems to be impossible to remove no matter what I do, I thought I finally got rid of it but it's back again. You can see a strack trace of the error on a similar post here.
Notes about the environment:
IIS 6.0, .NET 3.5 SP1 single server ASP.NET application
Steps already taken:
<system.web>
<machineKey validationKey="big encryption key"
decryptionKey="big decryption key"
validation="SHA1" decryption="AES" />
In my Page Base for all of my pages
protected override void OnInit(EventArgs e)
{
const string viewStateKey = "big key value";
Page.ViewStateUserKey = viewStateKey;
}
Also in the source of the page I can see that all of the ASP.NET generated hidden fields are correctly at the top of the page.
First of all lets start from the fact, that this error of view state happens on PostBack.
Also I must say that I have done all the things that every one suggest to do to avoid this problem. And I have single machine, but 2 pools that run the same Pages.
So someone do an action, ether a man, ether some other search machine by 'clicking' on your pages, or some hacker try to check your system for problems...
I have similar problems (rare but existing ones), and I finally found that people try to hack-test my pages. (from the same IP I have and dos attacks)
I modify the function LoadPageStateFromPersistenceMedium() that translate the viewstate, and see by logging what exactly was the input, and from what IPs... then I started monitor these results and see that the view state was changed by hand - or was totally empty.
On error I just redirect him to the same page...
Here is what I did...
public abstract class BasePage : System.Web.UI.Page
{
protected override object LoadPageStateFromPersistenceMedium()
{
try
{
.. return the base, or make here your decompress, or what ever...
return base.LoadPageStateFromPersistenceMedium();
}
catch (Exception x)
{
string vsString = Request.Form[__VIEWSTATE];
string cThePage = Request.RawUrl;
...log the x.ToString() error...
...log the vsString...
...log the ip coming from...
...log the cThePage...
// check by your self for local errors
Debug.Fail("Fail to load view state ! Reason:" + x.ToString());
}
// if reach here, then have fail, so I reload the page - maybe here you
// can place somthing like ?rnd=RandomNumber&ErrorId=1 and show a message
Responce.Redirect(Request.RawUrl, true);
// the return is not used after the redirect
return string.Empty;
}
}
Second Reason
Now there is one more reason why this can happen, and the reason is because some one click on your page before the __EVENTVALIDATION is loaded.
This eventValidation is placed on the last button-even that asp.net found, and if you have some of them on many place on the page, or near the button, then this go to the end of the page.
So even if you see the viewstate on the top of the page, where is the Validation ??? maybe this never loaded - page corrupt ?, too fast user click on page ?
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" ... >
To avoid this kind of problem I made a simple javascript that I do not let it press the button unless this input have been loaded !!!.
One more comment, the __EVENTVALIDATION is not always presents ! so is maybe safer not to search for this field if you make a general solution, but to make a javascript trick to just check if the full page is loaded, or something else that you think.
Here is my final solution with jQuery: (note that I check on PageLoad if eventvalidation exist !). I have this placed on my MasterPages.
<script language="javascript" type="text/javascript">
function AllowFormToRun()
{
var MyEventValidation = $("#__EVENTVALIDATION");
if(MyEventValidation.length == 0 || MyEventValidation.val() == ""){
alert("Please wait for the page to fully loaded.");
return false;
}
return true;
}
</script>
protected void Page_Load(object sender, EventArgs e)
{
// I do not know if Page can be null - just in case I place it.
if (Page != null && Page.EnableEventValidation)
{
Form.Attributes["onsubmit"] = "return AllowFormToRun();";
}
}
You can test by placing near the button of your page a delay.
<% System.Threading.Thread.Sleep(5000); %>
Update
Today I see in log this message again for WebResource and what I discover is that a bot getting the pages and make all the character on the links in lower case, including the parameters, so this was one more reason to not getting the correct encoded string, and throw a message like Padding is invalid and cannot be removed.
Hope this help you more.
A survey of the web pages found with several of the keywords from the error message indicate that this type of error is relatively common, usually random (at least in appearance) and unfortunately rarely inclusive of an explicit work-around or explanation...
The existence of many similar-yet-different situations is probably tied to the very many different architectures and underlying configurations which can somehow lead to the inability of the crypto layer to assert the authenticity of the MAC (Message Authentication Codes) in the request pages:
Server farm setup
Cross domain / syndicated pages
third party widget libraries and such
Actual ASP program logic (of course)
One relatively frequent "marker" around these bug reports is the mention of resource requests (eg. WebResource.axd).
Note that such requests are often not logged (lest they inflate the log files size with event of relative little interest). This absence from the log file and the fact they are often cached (and hence the relative random and infrequent occurrence of the bug) may explain how this possible origin of the bug go "under the radar". This also suggests that in trying to recreate the bug, (while tracking in the logs, in real time etc) it may be useful to prevent the web browser from caching (or for the least to clear it cache initially).
In short, here are a few ideas and things to look for:
start logging the *.axd requests
try and co-relate such axd requests with the error events in the exception log
look for pages with resource references
if in a Farm setting, ensure that all instances use the same key (apparently the snippet provided in the question hint at multiple IIS servers)
Be suspicious of pages with 3rd party tie-ins (search services, affiliate programs...)
Hope this helps ;-)
Are you sure your problem is cryptography related, and not caused by oversized ViewState?
If ViewState is the problem, you can chunk it - change the value of pages / MaxPageStateFieldLength in web.config