MVC web site: localhost page can’t be found http error 404 - asp.net-core

I'm developing a Asp.net MVC Core 2.2 web site in IIS.
The IIS website that hosts my MVC Core project has been created correctly. My project generates correctly a PDF file. Usually, I just use a jquery function to open that PDF file in browser:
$.ajax({
url: '#Url.Action("CreatePDF", "MyApiController", new { area= "MyArea" })',
dataType: 'json',
contentType: "application/json",
type: 'POST',
cache: false,
data: JSON.stringify(Filtro),
success: function (d) {
if (d.success == true) {
var item = d.data;
var pageurl = '#Url.Content("~/")' + 'Temporal/' + item.PDFName;
window.open(pageurl, '_blank');
}
},
However, I just realized that this MVC Core web site doesn't allow to open any PDF or txt or jpg or whatever file in browser and instead output this message:
localhost page can’t be found
http error 404
My question is:
In a MVC Core web site, how should I open a PDF file in browser from Controller
[Route("[action]")]
[HttpPost]
public ActionResult<BE_Reporte> CreatePDF(BE_Reporte c)
{
BL_Reporte b = new BL_Reporte();
try
{
c = b.CreatePDF(c);
return Ok(new
{
data = c,
success = true,
Message = "PDF created OK"
});
}
catch (Exception ex) { throw ex; }
finally
{
b.Dispose(); b = null;
}
}

The generated Url for '#Url.Content("~/")' + 'Temporal/' + item.PDFName; will be something like /Temporal/Test.pdf. For this request url, you need to place the Test.pdf in the place CoreMVC2_2\wwwroot\Temporal\Test.pdf.
If you place the Temporal in other folder except wwwroot, it is recommended to move it to wwwroot, otherwise, you need to configure the Serve files outside of web root.
And for client side, you may need to try code below:
var pageurl = '#Url.Content("~/")' + 'Temporal/' + 'Test.pdf';
console.log(pageurl);
var newWindow = window.open("", '_blank');
newWindow.location = pageurl;

Hey the 404 Error says the server did not find the resource you requested. First try to place a break-point at the beginning of the controller action CreatePDF. Then change your attribute routing to [HttpPost("[action]")] and remove the leading [Route("[action]")] call as it might be causing a routing error.
Also, try and add [FromBody] before your parameter.
...([FromBody] BE_Reporte ...)
Also you can use <iframe> HTML tag to display a pdf file or use <embed>
as noted here: Load Generated PDF Data into IFRAME on ASP.NET MVC

Related

How to download Blazor server page html result

Under Asp.Net MVC I used to build the body of my mailing messages on a MVC view which the system downloaded through System.Net.HttpWebRequest.
Now that I am migrating to Blazor server, I can browse the page but if I try to download it to fill the body of the message I always get next body:
Loading... An unhandled exception has occurred. See browser dev
tools for details. Reload X
I tried both through a Blazor page and through a Cshtml razor page. My browser can see both successfully but I always get the same exception.
This is the code I use to download the page:
HttpResponseMessage response = await http.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var contentType = response.Content?.Headers?.ContentType?.MediaType;
if (contentType == "application/json" | contentType == "text/html")
{
string responseText = await response.Content?.ReadAsStringAsync() ?? "";
if (typeof(T) == typeof(string))
retval.Value = (T)(object)responseText;
else
retval.Value = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText);
}
else
{
byte[] result = await response.Content.ReadAsByteArrayAsync();
retval.Value = (T)Convert.ChangeType(result, typeof(T));
}
}
}
I finally discovered the problem was on Program.cs from my .Net7 Server side Blazor app.
I was registering HttpClient as follows:
var http = new HttpClient();
builder.Services.AddScoped(sp => http);
This was Ok to access API data, but for some reason if you try to download a Html page source it throws a System.ObjectDisposedException: Cannot access a disposed object.
The right way to register the service to avoid this exception is:
builder.Services.AddHttpClient();
The problem is I no longer have a http variable in Program.cs, which I used to preload data from Api before the index page was ready.
Need a bit more detail:
What line threw the exception?
What was the exception?
What was value of string responseText or byte[] result?
I suspect either the DeserializeObject or Convert.ChangeType call failed. You should debug this; the answer will probably become apparent as you step through the code.

ASP.Net Core Web Api not working after calling page published to server

I have a relatively simple web api call that sends an email. everything works fine when I use postman or when I make the call from javascript on an html page running on my computer. I published the web api to my azure site and the call still works in postman and on the locally running page. However, I have published the exact html page to 2 different web servers and the email no longer sends.
here is the relevant javascript, the url is obfuscated. I would prefer that it was not public
function sendEmail() {
var uri = "http://mysubdomain.azurewebsites.net/api/shirt";
//var uri = "https://localhost:44337/api/shirt";
//alert("hello");
const email = {
CustomerName: $('#custName').val(),
CustomerSchool: $('#custSchool').val(),
CustomerEmail: $('#custEmail').val(),
CustomerPhone: $('#custPhone').val(),
Design: $("input[name='designradios']:checked").val(),
Mascot: $("input[name='mascotradios']:checked").val(),
PrimaryColor: $('primColor').val(),
SecondaryColor: $('secColor').val(),
TertiaryColor: $('tertColor').val(),
Font: $("input[name='fontradios]:checked").val()
}
//alert(email.CustomerEmail);
$.ajax({
url: uri,
type: "PUT",
accepts: "application/json",
contentType: "application/json",
data: JSON.stringify(email),
success: function (result) {
//getData();
//alert(result);
}
});
}
Here is the controller method. If sure there is a better way to do this, and I would be glad to find a better way, but I need something that works.
public ActionResult PutShirt([FromServices] IEmailService Mailer,Email email)
{
EmailAddress customerEmailAddress = new EmailAddress();
customerEmailAddress.Name = email.CustomerName;
customerEmailAddress.Address = email.CustomerEmail;
EmailAddress catalystEmailAddress = new EmailAddress();
companyEmailAddress.Name = "Company";
companyEmailAddress.Address = "info#company.net";
EmailMessage message = new EmailMessage();
message.ToAddresses.Add(customerEmailAddress);
message.ToAddresses.Add(companyEmailAddress);
message.FromAddresses.Add(companyEmailAddress);
message.Subject = "test";
message.Content = "This is a test";
Mailer.Send(message);
return StatusCode(200);
}
I have published the exact html page to 2 different web servers and the email no longer sends.
it looks like it might be an issue with Cors, but I am having trouble getting that to work as well
If your back-end service/app is hosting on Azure App Service, you can try to configure and enable CORS for your app on Azure portal, like below.

Redirect HTTP to HTTPS in MVC4 Mobile Application

In My MVC4 Mobile application i have registration, login page and remaining pages. i would like to redirect user to HTTPS connection for all sensitive information pages like registration and login pages and HTTP to remailing pages.
I prefer you to use conditional functionality putting the class
public class RequireHttpsConditional : RequireHttpsAttribute
{
protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
var useSslConfig = ConfigurationManager.AppSettings["UseSSL"];
if (useSslConfig != null)
{
if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The requested resource can only be accessed via SSL.");
}
var request = filterContext.HttpContext.Request;
string url = null;
int sslPort;
if (Int32.TryParse(useSslConfig, out sslPort) && sslPort > 0)
{
url = "https://" + request.Url.Host + request.RawUrl;
if (sslPort != 443)
{
var builder = new UriBuilder(url) { Port = sslPort };
url = builder.Uri.ToString();
}
}
if (sslPort != request.Url.Port)
{
filterContext.Result = new RedirectResult(url);
}
}
}
}
and using this [RequireHttpsConditional] above the action result.
i have got this code somewhere in internet and is working fine for me.
in web.config appsettings use <add key="UseSSL" value="443" />
and in the controller above the action result you need put
[RequireHttpsConditional]
public ActionResult SignIn()
{
}
In IIS where you have your project right click and click "Edit Bindings" then you add a custom type https and port no 443 (you can change it)
Note this will work only in production environment. when executed locally it wont be working.
When you execute it locally you have request.Url.Host which will return you only localhost and missing your port number. so if you use it in MVC you will find error loading page for your pages where you put this code.
So this will work when you have the host assigned instead of using the localhost with a specific port number.
Within the controller actions that you wish to be HTTPS add the following code to the top of the method (of course you can simply add this to its own method and then call it):
if (!HttpContext.Request.IsSecureConnection)
{
var url = new UriBuilder(HttpContext.Request.Url);
url.Scheme = "https";
Response.Redirect(url.Uri.AbsoluteUri);
}
It is recommended though that you keep HTTPS on throughout your site to protect against a MITM attack against the auth cookie.

page Redirect in ASP.Net MVC + Web Api + AngularJs

I am building a ASP.Net MVC application that can work both in Web and JQuery mobile. So i am creating a seperate view for Web and JQuery mobile application. I have placed all my primary business logic services as a Web Api calls which are called by both the clients using the AngularJs which is working fine so far.
Now I was looking to introduce the security in to the application, and realized that Basic authentication is the quickest way to get going and when I looked around I found very nice posts that helped me build the same with minimal effort. Here are 3 links that I primarily used:
For the Client Side
HTTP Auth Interceptor Module : a nice way to look for 401 error and bring up the login page and after that proceed from where you left out.
Implementing basic HTTP authentication for HTTP requests in AngularJS : This is required to ensure that I am able reuse the user credentials with the subsequent requests. which is catched in the $http.
On the Server Side :
Basic Authentication with Asp.Net WebAPI
So far so good, all my WebApi calls are working as expected,
but the issue starts when I have to make calls to the MVC controllers,
if I try to [Authorize] the methods/controllers, it throws up the forms Authentication view again on MVC even though the API has already set the Authentication Header.
So I have 2 Questions:
Can We get the WebApi and MVC to share the same data in the header? in there a way in the AngularJS i can make MVC controller calls that can pass the same header information with authorization block that is set in the $http and decode it in the server side to generate my own Authentication and set the Custom.
In case the above is not possible, I was trying to make a call to a WebApi controller to redirect to a proper view which then loads the data using the bunch of WebApi calls so that user is not asked to enter the details again.
I have decorated it with the following attribute "[ActionName("MyWorkspace")] [HttpGet]"
public HttpResponseMessage GotoMyWorkspace(string data)
{
var redirectUrl = "/";
if (System.Threading.Thread.CurrentPrincipal.IsInRole("shipper"))
{
redirectUrl = "/shipper";
}
else if (System.Threading.Thread.CurrentPrincipal.IsInRole("transporter"))
{
redirectUrl = "/transporter";
}
var response = Request.CreateResponse(HttpStatusCode.MovedPermanently);
string fullyQualifiedUrl = redirectUrl;
response.Headers.Location = new Uri(fullyQualifiedUrl, UriKind.Relative);
return response;
}
and on my meny click i invoke a angular JS function
$scope.enterWorkspace = function(){
$http.get('/api/execute/Registration/MyWorkspace?data=""')
.then(
// success callback
function(response) {
console.log('redirect Route Received:', response);
},
// error callback
function(response) {
console.log('Error retrieving the Redirect path:',response);
}
);
}
i see in the chrome developer tool that it gets redirected and gets a 200 OK status but the view is not refreshed.
is there any way we can at least get this redirect to work in case its not possible to share the WebApi and MVC authentications.
EDIT
Followed Kaido's advice and found another blog that explained how to create a custom CustomBasicAuthorizeAttribute.
Now I am able to call the method on the Home controller below: decorated with '[HttpPost][CustomBasicAuthorize]'
public ActionResult MyWorkspace()
{
var redirectUrl = "/";
if (System.Threading.Thread.CurrentPrincipal.IsInRole("shipper"))
{
redirectUrl = "/shipper/";
}
else if(System.Threading.Thread.CurrentPrincipal.IsInRole("transporter"))
{
redirectUrl = "/transporter/";
}
return RedirectToLocal(redirectUrl);
}
Again, it works to an extent, i.e. to say, when the first call is made, it gets in to my method above that redirects, but when the redirected call comes back its missing the header again!
is there anything I can do to ensure the redirected call also gets the correct header set?
BTW now my menu click looks like below:
$scope.enterMyWorkspace = function(){
$http.post('/Home/MyWorkspace')
.then(
// success callback
function(response) {
console.log('redirect Route Received:', response);
},
// error callback
function(response) {
console.log('Error retrieving the Redirect path:',response);
}
);
}
this finally settles down to the following URL: http://127.0.0.1:81/Account/Login?ReturnUrl=%2fshipper%2f
Regards
Kiran
The [Authorize] attribute uses forms authentication, however it is easy to create your own
BasicAuthenticationAttribute as in your third link.
Then put [BasicAuthentication] on the MVC controllers instead of [Authorize].

Jquery Ajax call to WCF ajax enabled web service not working on Firefox

I have created a WCF ajax enabled web service named "Service1.svc"
"I have to call this Service In another app's using Jquery."
I have created on method in it :
[OperationContract]
public string GetMarkup()
{
string data = "<div>My HTML markup text here</div>";
return data;
}
Now I have created jquery script in my second application's html page :
var markup = "";
$.ajax({
type: "POST",
url: "http://localhost:1676/MyWCFService.svc/GetMarkup",
contentType: "application/json",
data: "{}",
dataType: "json",
success: callback,
error: function (textStatus) {
alert("ERROR");
}
});
function callback(result) {
alert("Inside Callback");
markup = result.d;
$("#divMyMarkup").html(markup);
alert(markup);
}
NOW, My Problem is that Whenever I execute this page in IE its working fine.
But In Firefox its not working. It giving alert Error Message which defined in
error: function (textStatus) {alert("ERROR");} in above ajax call.
I tried this functionality using $.get(), $("#divMyMarkup").load(serviceUrl, callback).
I also tried this by changing the datatype as json, jsonp, html .
Still I am not getting the exact solution.
Any Expert here?
In another app's using Jquery
In my experience, IE won't respect the cross-domain policy and let you do the call, not a reference...
The only way to find out is to have your html page/JQuery script calling your WCF service from http://localhost:1676/ICallWcfServicesWithJQuery.html on Firefox.
Possible solutions:
[JSONP] how to avoid cross domain policy in jquery ajax for consuming wcf service?
[flXHR][php-proxy] jQuery “getJSON” from an external domain that doesn't support JSON-P output
[JSONP] Accessing web Service from jQuery - cross domain
[.net-proxy] aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript
Test on multiple browsers, add 1oz of gin, a can of tonic and you'll be good!