ASP.NET C# Response.Write doesn't display message - c#

So I am told just by using Javascript inside the Response.Write method, I can display an alert/message box on ASP.NET C#.
Using Response.Write("<script>alert('Data inserted successfully')</script>") as the template given in other answers.
When I first attempted to use it, it worked, displaying the message and redirecting me sucessfully. Since then, it has not worked, I only changed the message to display and also where the redirect URL would go after. Logically it is working as it is taking me back to the application form, it just isn't displaying the message.
Can anyone explain why it suddenly doesn't work?
Code;
public ActionResult UpdateApplication(int ApplicationId, ApplicationEdit applicationEdit)
{
if(applicationEdit.Firm == false)
try
{
applicationService.UpdateApplication(applicationEdit, ApplicationId);
return RedirectToAction("GetUser", "User", new { ApplicationId = applicationEdit.ApplicationId });
}
catch
{
return View();
}
else
{
Response.Write("<script language=javascript>alert('Sorry, You can only have 1 firm application to send off, please update the old application and untick firm option on other application first.')</script>");
return RedirectToAction("UpdateApplication", new { ApplicationId = applicationEdit.ApplicationId });
}
}

Because you're redirecting the user:
return RedirectToAction("UpdateApplication", new { ApplicationId = applicationEdit.ApplicationId });
This returns a redirect HTTP code to the browser (HTTP 307 or 308 I imagine) which tells the browser to direct the user to the specified URL. Since the browser knows it's redirecting the user, it has no reason to render any content in the response.
Either return content to be rendered in the browser or return a redirect response, but not both. If you return the view instead then you should see your <script> element in the resulting response. If you want to redirect then any message you want to display to the user should be on that next page, not in the current response.
As an aside, using Response.Write in an ASP.NET MVC application is pretty much always the wrong approach. Any client-side code should be in or referenced by the view, and you can use data on the view's model to conditionally render or not render that content.

Related

Blazor page's URL is interfering with component's call to API -- 400-Bad Request

My web-app is .Net 6, VS-2022 Blazor WASM-hosted.
I am having a problem with the URL for the API when being called from a component.
I have three files: page: VehicleList.razor, page: VehicleEdit.Razor and component: CRUD_Vehicle.razor.
The page flow is the user navigates to 'VehicleList' and has the ability to select a vehicle to EDIT via callback function. Once selected, the flow navigates to 'VehicleEdit' where some data needs to be passed to support the embedded sub-component 'CRUD_Vehicle'.
The problem is that URL to the 'VehicleEdit' looks like this with query-string data in a comma-delimited string AND it remains there when the CRUD-component is showing.
https://localhost:7777/vehicleedit/667?par=17,Bigelow,Active
When the user makes editing changes and SUBMITs the component, the HttpClient service gets called and fails with a 400-Bad Request. I am under the impression that the query-string interfers with the api URL. Please see below. Is there a way I could set the URL to not show the query-string and only have the base-address and the UID_VEHICLE like this?
https://localhost:7777/vehicleedit/667
public async Task<Vehicle> UpdateVehicle(Vehicle pVehicle) {
// Save the edited record.
HttpResponseMessage response = await httpClient.PutAsJsonAsync<Vehicle>($"/api/vehicle/{pVehicle.UID_VEHICLE}", pVehicle);
if (!response.IsSuccessStatusCode) {
// problems handling here.
Console.WriteLine($"UpdateVehicle() Error occurred, the status code is: {(int)response.StatusCode}: {response.StatusCode}" );
}
return await response.Content.ReadFromJsonAsync<Vehicle>();
}
I have a similar construction for the editing of the Customer object, but the page that shows the CRUD_Customer component has a simple URL and works perfectly to save data to the DB. The main difference is the URL for the VehicleEdit.razor. Your comments are welcome.
Thanks.
https://localhost:7777/customeredit/17
I downloaded Postman and entered the PUT transaction and the PUT RESULT showed there was an ERROR (based on DataAnnotation for the 'StartDate'-field) that was NOT caught at the client validation code. It turns out that the TITLE text was based on what the possible cause might be. But Postman showed me the exact reason why the PUT call failed.
So, my 'answer' is: Use Postman to simulate the 'httpClient.PutAsJsonAsync'-call to observe the result-details to pinpoint the reason for the '400-Bad Request' return from the service.

How to Redirect to external url from controller in blazor webassembly?

I know that this question has already been asked but no answer has helped me to solve my problem.
I am using blazor webassembly, in the login module I send a confirmation email to the new user, in the message that comes to the email comes a confirmation link, which redirects to a custom blazor confirmation page that welcomes the system,
everything works fine in localhost, but when I publish the app on an iis server, the confirmation link does not redirect me to the welcome page, it stays in the link path, and in the app it shows me that it could not find the path.
Could you please help me
this is my code to send the confirmation message to the mail, This link is within a Send Mail method which contains all the information to send emails
var confirmationUrl = $"https://{Request.Host.Value}/api/Cuentas/VerifyEmailAsync?userId={HttpUtility.UrlEncode(userIdentity.Id)}&emailToken={HttpUtility.UrlEncode(emailVerificationCode)}";
This endpoint is the one that redirects to the welcome page once the user clicked on the link that I describe above in this publication:
[AllowAnonymous]
[Route("VerifyEmailAsync")]
[HttpGet]
public async Task<ActionResult> VerifyEmailAsync(string userId, string emailToken)
{
// Get the user
var user = await _userManager.FindByIdAsync(userId);
// If the user is null
if (user == null)
// TODO: Nice UI
return Content("Usuario no encontrado");
// If we have the user...
// Verify the email token
var result = await _userManager.ConfirmEmailAsync(user, emailToken);
// If succeeded...
if (result.Succeeded)
{
//se usa redirect para enviar a una pagina blazor desde el controlador
//return Content("Correo Verificado");
return Redirect($"https://{Request.Host.Value}/cuentaconfirmada");
}
// TODO: Nice UI
return Content("Token de verificación de correo electrónico no válido");
}
clicking on the link takes me to the following route:
https://beta.dominio.mx/api/Cuentas/VerifyEmailAsync?userId=7cc3a7b0-7f40-4d23-abe4-f6778877d6fa&emailToken=CfDJ8BaQjrGRmsNBsbOJm8bucuOua9CJS4w%2fvwySE%2bk0I%2btQYzfBc%2bysKqkCR9nwHDP7wmHzAkgYo%2fUiURHwnQd113wslk8Lgo5iqgAPxKWX17x0PYFF8y%2bih9BFtzD4RiOn%2bZXsZLDWqcga1tjHcDmYfhzh9NwWFZv8AhdLF48BusPZ9bsXiHEUK1WVY8Wgi7j601p%2fRds%2f7TY3rjq6BqpSyHiud3stD16xL5jgn1fLbinlzgm5%2bHvWegmXa2WICgL01A%3d%3d
the original route where it should take me is:
https://beta.dominio.mx/cuentaconfirmada
in the console it shows me that everything was successful it shows me the path that it really is and a status of 200 but it shows me a warning:
until I forcefully update it takes me to the correct path
I already tried to use other redirection methods, thinking that the problem comes from the http states that each method returns, use the following:
Redirect() 302
RedirectPermanent() 301
RedirectPreserveMethod 307
Just a thought, since you only have the code from the controller posted. You have allowed anonymous in the controller... but did you do so in the web page?
#layout AllowAnonLayout
I am attempting something similar. However in my case everything seems to work, but sometimes the redirection hangs after the user has been authenticated and I get a blank page.
I did find this article which I think may be pretty helpful... but in this article they are performing the page redirects from the server... which is why I am researching if redirecting from the server is possible in WASM when I came across this post.

Response is not being written after Response.End() when request departs from asp:multiview or ajax

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.

Server cannot set status after HTTP headers have been sent - ELMAH

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.

C# screen scraping an ASP.NET web forms page - POST request not completely working

Please bear with me for this slightly long winded description but I'm having a strange problem with C# screen scraping an ASP.NET web forms page. The steps I'm trying to do are as follows:-
1) The site is secured using basic authentication over HTTPS so I need to login appropriately.
2) I'm performing a GET request on the page to retrieve the __VIEWSTATE value (darn thing does nothing if I don't set this thing!)
3) Once logged in there are several form fields to complete then a submit button which POST's the form to the server
4) When the submit button is pressed the form is POST'd to the server and response is the same page and form but now with an extra little HTML table at the bottom of the form with some data I need to get at.
I've so far managed to sort the login and form post using the WebClient class. I've used fiddler (and firebug) to check the POST field values that are being sent when completing the form normally using a browser. I can successfully get a response from the POST request with the data table in question appearing below the form as expected. The problem however is that although the table is populated with data it is populated with data I don't expect. The data that appears is if I completed the form in a browser as normal but with one particular parameter (a drop down list) set to a different value than I'm passing in my POST request to the server. I've confirmed using fiddler and firebug that I'm passing exactly the same POST parameters that are sent as normal using a web browser human completed form. I'm now totally stuck as to why this one parameter is not being 'taken into consideration' by the server?
The one difference is that this particular control is a select list and it performs a page reload or 'postback' when changed. However this doesn't seem to do anything apart from change some other select lists content later in the form.
I guess I'm asking is there anything else I'm missing that would cause this? I'm totally tearing my hair out on this one. Can anyone help? I've posted the code below (with addresses and parameters blanked out for privacy).
// a place to store the html
string responseBody = "";
// create out web client to handle the request
using (WebClient webClient = new WebClient())
{
// space to store responses from the remote site
byte[] responseBytes;
// site uses basic authentication over HTTPS so we'll need to login
CredentialCache credentials = new CredentialCache();
credentials.Add(new Uri(Url), "Basic", new NetworkCredential(Username, Password));
// set the credentials in the web client
webClient.Credentials = credentials;
// a place for __VIEWSTATE
string viewState = "";
// try and get __VIEWSTATE from the web site
try
{
responseBytes = webClient.DownloadData(Url);
viewState = GetHtmlInputValue(Encoding.UTF8.GetString(responseBytes), "__VIEWSTATE");
}
catch (Exception e)
{
bool cancel = false;
ComponentMetaData.FireError(10, "Read web page data", "Error whilst trying to get __VIEWSTATE from web page: " + e.Message, "", 0, out cancel);
}
// add our POST parameters (don't forget the __VIEWSTATE or it won't work as its an ASP.NET web page)
NameValueCollection requestParameters = new NameValueCollection();
// add ASP.NET fields
requestParameters.Add("__EVENTTARGET", __EVENTTARGET);
requestParameters.Add("__EVENTARGUMENT", __EVENTARGUMENT);
requestParameters.Add("__LASTFOCUS", __LASTFOCUS);
// add __VIEWSTATE
requestParameters.Add("__VIEWSTATE", viewState);
// all other form parameters
requestParameters.Add("btnSubmit", btnSubmit);
/* I've hidden the rest of the parameters hidden for privacy just in case */
// see if we can connect and get data
try
{
// set content type
webClient.Headers.Clear();
webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
// 'POST' the form data using web client and hope we get a response
responseBytes = webClient.UploadValues(Url, "POST", requestParameters);
// transform the response to a string
responseBody = Encoding.UTF8.GetString(responseBytes);
}
catch (Exception e)
{
bool cancel = false;
ComponentMetaData.FireError(10, "Read web page data", "Error whilst trying to connect to web page: " + e.Message, "", 0, out cancel);
}
}
Please ignore the 'ComponentMetaData' references as this is part of SSIS script source.
Any ideas or help will be greatly appreciated - cheers!
RE: thanks for the quick responses, all I can say to those comments is...
There's the normal ASP session cookie but there's no values in the cookie (apart from the session ID of course), I figured as the site is using basic authentication not forms authentication I could just ignore the cookie - and as I'm getting into the site and getting data returned this was ok. I guess it's worth a try but I'll have to just alter the code to use the WebRequest class method instead...
As for the select list javascript, no there's no javascript changing the value of the select list after page load. The only javascript on the select list is an onchange event to do a 'postback' which only seems to change some other select lists on the form that are empty anyway in the final POST. Note I'm including all the POST parameters when generating the POST request even if they're empty and I'm also including all the 'web forms' special fields such as __VIEWSTATE, __EVENTTARGET etc...
I'm no expert in web forms (MVC man myself) but is there anything else that the web forms 'engine' is expecting? I've sent 1 header for the 'Content-Type' of 'application/x-www-form-urlencoded' but I've tried setting others such as copying the 'User-Agent' header from the original POST but this ends up with me getting a 500 error from the server, not sure why that would happen??
Here's the code for the 'GetHtmlInputValue' its a bit simple/basic and could be done better but:-
private string GetHtmlInputValue(string html, string inputID)
{
string valueDelimiter = "value=\"";
int namePosition = html.IndexOf(inputID);
int valuePosition = html.IndexOf(valueDelimiter, namePosition);
int startPosition = valuePosition + valueDelimiter.Length;
int endPosition = html.IndexOf("\"", startPosition);
return html.Substring(startPosition, endPosition - startPosition);
}
If I understand you correctly, then selecting an item in the dropdown will cause a POST to be performed, and the server alters the available options in another part of the form. The server will then include the current value of the dropdown in the __VIEWSTATE field value.
When you perform the scraping, you should make sure that the __VIEWSTATE contains the desired value for the dropdown. To investigate further, try to decode the viewstate from the server and see which values are sent back.

Categories

Resources