In my interface I defined:
[OperationContract]
[WebInvoke(Method = "DELETE",
UriTemplate = "deleteAsset/{asset_id}")]
void deleteAsset(string asset_id);
My implementation is as follows:
public void deleteAsset(string asset_id)
{
using (DataClassesDataContext thisContext = new
DataClassesDataContext(ConfigurationManager.ConnectionStrings
["mgatewayConnectionString"].ConnectionString))
{
var result =
thisContext.spGetAssetById(Convert.ToInt32(asset_id)).FirstOrDefault();
if (result != null)
{
thisContext.spDeleteAsset(Convert.ToInt32(asset_id));
thisContext.spDeleteModuleAssetLink(Convert.ToInt32(asset_id));
}
}//using
}
I use RESTClient for Firefox for testing. I chose DELETE from the Method dropdown list and entered the url: localhost:57518/Service.svc/deleteAsset/127 and hit "Send" button. Then I got this error. I got the following error message:
400 Bad Request
The server encountered an error processing the request.
The problem is probably not in the code you've posted.
a 400 error should generally only happen if you send a malformed http request. So whatever way you're testing it, the web server is rejecting it befire it hits your method.
where is it happening? does it reach the "deleteAsset" methid?
Also, why are you checking if the asset exists before deleting? It seems like an unnecessary overhead. Cant you just run the delete command and if it exists it will be deleted, otherwise nothing will happen. If you need to know if something was actually deleted or not, get the affected rows from the delete command.
Related
I do understand that I might be getting this wrong since I am porting asp.net application to asp.net core 2.0 (mainly because the optimizations regarding load speed on pages) but I would ask the question anyway.
So my queries are working properly when I am fetching data only, however, I ran into a problem while having to fetch a file path from the database in order to download it on the client side. Since I don't need the whole model of the file I have 3 field dto on the client side that I fill up with the information regarding the file (etc location, size, filename) the problem is that when I send the async request toward the WCF service on Azure that's hold my entity framework link to the database the code continues further without waiting for the data to be retrieved from the database and throws null reference exception while attempting to fill the dto object that is to be sent further to the client in order to retrieve the file that's marked for downloading
This is my data access on the client side
internal async Task<AnimalDocument> GetAnimalDocument(int id)
{
var data = await _context.GetAnimalDocumentAsync(id);
var result = JsonConvert.DeserializeObject<AnimalDocument>(data);
return result;
}
And this is where I get the null exception
public SeriliazedFile GetFile(int id, int type)
{
var result = new SeriliazedFile();
if (type == 1)
{
var data = _context.GetHumanFile(id);
result.FileName = data.Result.DocumentName;
result.FilePath = data.Result.DocumentLocation;
result.FileSize = data.Result.FileSize.Value;
}
else if (type == 2)
{
var data = _context.GetAnimalDocument(id);
result.FileName = data.Result.DocumentName;
result.FilePath = data.Result.DocumentLocation;
result.FileSize = data.Result.FileSize.Value;
}
return result;
}
Is there a way to force the async request to wait for the result before returning Task that I retrieve from the WCF? I've tried telling _context.GetAnimalDocument(id).Wait(); however, nothing happens it still proceeds further without any result.I've noticed that the trigger to retrieve the data is fired after the ajax request that is sent toward the page returns 200 causing something like a deadlock but I might be wrong. If anyone could give me a work around it would be nice, I am pretty sure that I would figure it out on my own eventually but time is rare anyway, I hope you have a good day.
I am sorry for posting this, it was not a issue with the WCF or the code in any way, async works perfectly fine with asp.net core 2.0 the issue was with me. I am still adapting to the concept of have [FromBody] in front of the types in the functions, it appears to be that I missed one and I was getting id 0 by default (not that I can figure out why I would get 0 instead of null on integer field when there is no data but that doesn't matter anyway.) in my id field and the data layer was returning null value that's why I was getting null reference exception later.
I wrote a HttpModule to intercept, evaluate and authorize requests, checking if logged user has appropriate access to the url being requested, in a pretty old legacy system written in ASP.NET 2.0(Web pages, not Web app), whose customer does not want to port to a newer framework. Restrictions have been loaded and cached at login time.
Everything works fine, except when some page contains an <asp:MultiView> component or when there is a button that launch an ajax method. When one of these situations occur, and user doesn't have rights to access that url, an alert box pops up with an "Unknown error" message, that came from a ThreadAbortException thrown by Response.End() method.
The question is: Why does my "Unauthorized" message is being overwritten by "Unknown Error" from the exception, only on these two situations?
Is there a way of doing an Url Authorization system, using database and caching and without cluttering Web.config with roles like those older ASP.NET samples?
// My module init method.
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
// PreRequestHandlerExecute is the first stage at ASP.NET Pipeline
// where we could get a fulfilled Session variable
}
private void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
// additional request filtering/validation/etc.
LoggedUser user = (LoggedUser)application.Session["user"];
string path = context.Request.Path;
// more checks and rules...
if (!checkUserAuthorization(path, user))
{
context.Response.Write("<script>alert('Unauthorized. Contact your manager.');</script>");
context.Response.Write("<script>window.history.back();</script>");
context.Response.StatusCode = 403;
context.Response.End();
}
}
EDIT: What I've already tried (with no goal):
Response.OutputStream.Close();
Response.Flush();
HttpApplication.CompleteRequest();
it's by design. you must ignore it and add a catch for that exception.
try {
context.Response.End();
}
catch{}
Foreword
After a lot of research, finally I got it. Considering ASP.NET 2.0, concerning AJAX operations, the project I'm working uses a Microsoft component called "Atlas", which in turn got renamed to ASP.NET AJAX. At the time this system was written, the developers used the beta ASP.NET AJAX (codename "Atlas") to address all ajax and partial rendering needs.
I needed to dig deeper in source code (thanks to Reflector), to understand and inspect from where does that "Unknown Error" comes.
Inside the Microsoft.Web.Atlas, there is a file named Microsoft.Web.Resources.ScriptLibrary.*.Atlas.js (where * could be Debug or Release) which is rendered at runtime through a WebResource.axd "proxy".
This javascript file have a bug, because it expects to ASP.NET request always return an HTTP 200 (OK) response code, which in my code it's not happening (I'm returning a 403 Forbidden code at my module).
Code
From Microsoft.Web.Resources.ScriptLibrary.*.Atlas.js taken from WebResource.axd:
this._onFormSubmitCompleted = function(sender, eventArgs) {
var isErrorMode = true;
var errorNode;
var delta;
if (sender.get_statusCode() == 200) {
delta = sender.get_xml();
if (delta) {
errorNode = delta.selectSingleNode("/delta/pageError");
if (!errorNode) {
isErrorMode = false;
}
}
}
if (isErrorMode) {
if (errorNode) {
pageErrorMessage = errorNode.attributes.getNamedItem('message').nodeValue;
}
else {
pageErrorMessage = 'Unknown error';
}
this._enterErrorMode(pageErrorMessage);
return;
}
// Code continues.
}
From this code, we can see that since response code is not an 200 OK, that errorNode variable won't be set, and this if (errorNode) statement will always be false.
In this case, I was left with two options: Always return HTTP 200 and modify all pages that have an <atlas:ScriptManager> with and add an ErrorTemplate tag on each, or supersede that script with one that consider non-HTTP 200 responses, loading it below </form> tag at the Master page.
There is a lot of tutorials on how to do a proper error handling when using ScriptManager and UpdatePanels (an official one here), by subscribing to the AsyncPostBackError event), but this beta version (Atlas) simply don't have this event.
I have been receiving this error through ELMAH. Even though the program completes it's intended actions, I still receive this error through ELMAH and I'd like to know why and to fix it. I've gone through other threads and tried to use those suggestions but nothing I've read so far doesn't seem to work.
It's intended action is to create an excel document and then redirect the user to the page they were just on.
ActionResult:
public ActionResult ExportClaimNumberReport(int ClientID, string ClaimNo) {
ClaimNumberViewModel model = ClaimNumberReport(ClientID, ClaimNo);
CreateExcelFile.CreateExcelDocument(
model.ReportData.ToList(),
model.ReportDescription + (".xlsx"),
HttpContext.ApplicationInstance.Response);
ViewBag.client = client;
Response.Buffer = true;
Response.Redirect(Request.UrlReferrer.ToString());
if (!Response.IsRequestBeingRedirected) {
Response.Redirect("/Error/ErrorHandler");
}
return RedirectToAction("ErrorHandler", "Error");
}
If you need anymore info, just let me know
You will get the error because you are doing 2 redirects.
Once here
Response.Redirect(Request.UrlReferrer.ToString());
And then again here:
return RedirectToAction("ErrorHandler", "Error");
So the first redirect will write a redirect header to the response stream, then the second would try to do it again, but obviously you can't send http headers to the browser twice so it throws an exception. However the user won't notice because by the time the exception is thrown the browser has already been told to redirect elsewhere.
What you want to do is just call the Redirect method as the return statement from your controller action.
So replace all this:
Response.Redirect(Request.UrlReferrer.ToString());
if (!Response.IsRequestBeingRedirected) // this would always be false anyway
{
Response.Redirect("/Error/ErrorHandler");
}
return RedirectToAction("ErrorHandler", "Error");
With this:
return Redirect(Request.UrlReferrer.ToString())
Although why you are redirecting the browser back to the referring page is unclear.
I have created an MVC (4) Web API which works fine. It has a simple login-method that throws an exception when the user cannot be found.
Besides the API I created a simple website that calls the API by HttpClient:
public T ExecutePost<T>(string apiUrl, IEnumerable<KeyValuePair<string, string>> postData) {
HttpContent content = null;
if (postData != null)
content = new FormUrlEncodedContent(postData);
var a = _client.PostAsync(apiUrl, content).ContinueWith(httpResponseMessage =>
JsonConvert.DeserializeObject<T>(httpResponseMessage.Result.Content.ReadAsStringAsync().Result)
);
return a.Result;
}
You can call this method as
ExecutePost<User>("url_to_controller_action_api", list_with_keys_and_values_to_post)
When this method calls the API with the postData-fiels username and password (both are correct and known by the system) an object called User will be returned... Works like a charm.
When I call this method with the wrong username and/or password, the API throws an exception (User not found), but the method ExecutePost throws an exception aswell and the web page shows a nice, yellow-isch, red-letter page with errors that the normal user does not understand. The reason is easy: The data sent back from the API is not the same as the data that can be put in the object User.
So, what I would like to do is deserialize the exception, from the API, in an object called Error and return that to the controller of the MVC website, so I can put the error "User not found" on the page with the correct design of the site.
What is the best way to do this? Try-catch in all actions? Doesn't feel right to me... So suggestions are more than welcome.
Most things I found were API-side stuff, but I want to fetch and handle the exception on the site-side.
Thanks in advance
On your Web API when you detect an invalid login, make sure that an HttpResponseException gets thrown with a status code of 401 (HttpStatusCode.Unauthorized).
//login failed:
var resp = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("Invalid Username or password")
};
throw new HttpResponseException(resp);
In your calling code, you can then first check if httpResponseMessage.StatusCode==HttpStatusCode.OK before you attempt to deserialise the response into a User.
var a = _client.PostAsync(apiUrl, content).ContinueWith(httpResponseMessage => {
if (httpResponseMessage.Status!=HttpStatus.OK)
{
string ErrorMessage = httpResponseMessage.Result.Content.ReadAsStringAsync();
//and whatever you want to do with that error message here
}
else
{
try
{
var user = JsonConvert.DeserializeObject<T>(httpResponseMessage.Result.Content.ReadAsStringAsync().Result);
}
catch(Exception ex)
{
//honest to goodness unrecoverable failure on the webapi.
//all you can do here is fail gracefully to the caller.
}
}//endif (Status OK)
}//end anonymous function
);
If it's not a 200 then you can execute a second check to see if it's a 401 (and have some specific handling for invalid login) or a more general 500 (something went wrong on the server), etc, and get the actual error message of the exception ("Invalid Username or password") to send back to the client:
var errorMessage = httpResponseMessage.Content.ReadAsStringAsync().Result;
Finally, even if it is 200 then you should still try...catch the deserialisation operation so you can gracefully handle any issues with the returned data, if for whatever reason the data can't be turned into a User object.
I have a simple method that is secured
[PrincipalPermission(SecurityAction.Demand, Role = "Administrator")]
protected void lnkClearCache_Click(object sender, EventArgs e)
{
...
}
If this is clicked without the role, it generates a System.Security.SecurityException: Request for principal permission failed. as expected.
I use ELMAH to handle logging for my errors, and I have a custom ELMAH event in my global.asax to transfer to the error pages in ways that preserve status codes which works correctly.
private void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
{
var customErrorsSection = GetCustomErrorsSection();
var error = args.Entry;
string statusCode = error.Error.StatusCode.ToString();
if (statusCode == "0" && error is security exception)
statusCode = "403";
var errorSection = customErrorsSection.Errors[statusCode];
string redirectUrl = errorSection == null ?
customErrorsSection.DefaultRedirect : errorSection.Redirect;
RespondWithServerError(error.Id, redirectUrl, statusCode);
}
This works all well and fine and redirects to my error page which works properly, however instead of displaying the content as expected. I immediately get a second request for the error page but this time using the value of customErrorsSection.DefaultRedirect that does not come from my code in any way that I can see.
As far as I can tell it's almost as if when .NET raises an exception for PrincipalPermission and then lets the entire request complete, then after the request is complete it throws away the application response and instead responds with the default custom error.
When I'm debugging I do break on 2 separate exceptions for PrincipalPermission, whether this is a just a rethrow by .NET I'm not sure but my .NET code never sees the 2nd throw, nor does ELMAH. I always end up with a single response, single error logged, but that the url that finally renders to the browser is the default url and not 403 url that I specifically server.transferred to. If I browse to a /location that is secure I properly get the 403 error page.
I don´t excactly know where the problem is. But i´´m using something similar and for me this solution (minimized) works great.
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
Dim er = HttpContext.Current.Error
If er.GetType.Equals(GetType(System.Security.SecurityException)) Then
HttpContext.Current.Response.Redirect(FormsAuthentication.LoginUrl & "?ReturnUrl=" & HttpContext.Current.Request.Path)
End If
End Sub
That´s out of global.asax
But on some places I don´´t redirect, and just using try and catch the securityexception to display the user, that he is not allowed to perform such action.