Dynamically created css not working on Azure website - asp.net

I am working on Web Form project to deploy on production. In this project, dynamic folder is created on fly and put the new css style as per data configuration from database. This was handled by Handlers in web form. Application works locally without any error. But when I publish on production it does not find the dynamic created css file path. Its not physical exists it creates on fly. So it fails to download css and it missing all images and styles. Another team had developed this application and we are moving this from FireHost to Azure site. It was working on Firehost but no any luck on Azure site yet. I tried to remove manifest file in production by adding remove attributes .manifest in web.config. But no any luck yet. I appreciate your help Thanks
I am getting 404 errors,
Failed to load resource: the server responded with a status of 404 (Not Found)
I have the style css inject this way in site.master page.
<link href="/Styles/Dynamic/CompanySite.css" rel="stylesheet" type="text/css" />
It did not mentioned handlers in web.config. There is separate handlers folders and pages. In pages code behind file look like this in page load method.
StringBuilder sb = new StringBuilder(File.ReadAllText(Server.MapPath("~/Styles/CompanyStyles.css")));
string sPrimaryColor = "#B1D74C";
string sSecondaryColor = "#8BBB29";
string sPrimaryTextColor = "#000";
string sSecondaryTextColor = "#000";
string sBannerId = "1";
try
{
var settings = new CompanySettingDataLogic().Retrieve();
if (settings != null)
{
sPrimaryColor = settings.primary_color_txt;
sSecondaryColor = settings.secondary_color_txt;
sPrimaryTextColor = settings.primary_text_color_txt;
sSecondaryTextColor = settings.secondary_text_color_txt;
}
var BannerId = new CompanyThemeDataLogic().GetBannerId();
if (BannerId.HasValue)
sBannerId = BannerId.Value.ToString();
}
catch (Exception Ex)
{
new Data.Config.ErrorLogDataLogic().LogException(Ex);
}
sb.Replace("#PRIMARY#", sPrimaryColor);
sb.Replace("#SECONDARY#", sSecondaryColor);
sb.Replace("#PRIMARYTEXTCOLOR#", sPrimaryTextColor);
sb.Replace("#SECONDARYTEXTCOLOR#", sSecondaryTextColor);
sb.Replace("#BANNERIMAGEID#", sBannerId);
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Cache.SetCacheability(HttpCacheability.Private);
Response.Cache.SetExpires(DateTime.Now.AddDays(2));
Response.ContentType = "text/css";
Response.Write(sb.ToString());

Its not physical exists it creates on fly. So it fails to download css
and it missing all images and styles.
Where have you stored the files after the folder being created? Do you store them in website Azure vm disk? Please note
the VM disk storage is not persistent
if you have >= 2 instances on Azure to host the web app, and then you just created the css/images files on 1 instance (VM), later your end user may hit the other instance that has no such files.
so please store your files in Azure storage - blob and use its url in your project to connect to css/image files

Related

ASP.NET Core Web API & Entity Framework Core: physical storage not working on production server

I have an ASP.NET Core Web API where an endpoint uploads a PDF file. The current method to upload to physical storage (the hard disk) is this:
[HttpPost]
public async Task<ActionResult> Upload([FromForm] UploadModel uploadModel)
{
var fileName = System.IO.Path.Combine(_environment.ContentRootPath,
"uploads",
uploadModel.ImeiOrSerial + "" + uploadModel.EquipmentInvoice.FileName);
await uploadModel.EquipmentInvoice.CopyToAsync(
new System.IO.FileStream(fileName, System.IO.FileMode.Create));
using (var context = _context)
{
var equipment = new Equipment();
equipment.TypeOfEquipment = uploadModel.TypeOfEquipment;
equipment.EquipmentBrand = uploadModel.EquipmentBrand;
equipment.ModelOrReference = uploadModel.ModelOrReference;
equipment.ImeiOrSerial = uploadModel.ImeiOrSerial;
equipment.Path = uploadModel.ImeiOrSerial + "" + uploadModel.EquipmentInvoice.FileName;
_context.Equipment.Add(equipment);
await _context.SaveChangesAsync();
return Ok(await _context.Equipment.FindAsync(equipment.IdEquipment));
}
}
If I do this in development, everything works perfectly, I get the name of the PDF invoice and it gets in the uploads file inside the solution directory
But if try to do this on my IIS web server, it doesn't work.
I enabled swagger in production mode to see what error the swagger was throwing, but I only get this:
I have no clue what I'm doing wrong.
UPDATE
I wrap my post method in a try catch and now it shows me the following error:
Ady's comment is correct. By default, the uploads will not included in publish. You need enable it in your .csproj file. You can check the doc about Visual Studio publish profiles (.pubxml) for ASP.NET Core app deployment.
You can add below code to your .csproj file.
<ItemGroup>
<Content Include="uploads\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
If your uploads folder is empty, you can create a simple txt file in it or use MakeDir to create it when publish.
This is what I found that work for me, do the following:
Go to the IIS manager.
Right click on your backend page, in my case its called API:
Then go to Edit Permissions:
Select the option that says IIS_IUSRS, like shown in the previous image, then click in the edit button.
Pick again the option that says IIS_IUSRS and give permission to full control and modify.
Finally go to the wwwroot folder where you published your API and create a new folder where its gonna be located all the files. In my case I named the file "uploads"
And that's it, you should be able to upload files, and locate them in physical storage

Access static files on server from RCL

I've read dozens of questions but none seem to work for me. I'm not using IIS. I'm using ASP.Net Core 3.1 with Kestrel.
I have a Razor Class Library with a resources folder, in that I have folders like css, js, content, etc. I use this library so all of my common Web Api projects can share common files instead of duplicating them everywhere. To do this, I followed the guide from here. Please see there for how Startup is configured.
That works great, I can access those files by going to e.g. localhost/css/site.css. In my cshtml files, I can include that file by doing <link rel="stylesheet" href="~/css/site.css"/>
The problem arises when I try to access those files from a controller. I have a sister folder to css called content which contains json files. I can view that file by going to localhost/content/test.json, but I can't figure out how to access it from a controller.
What I'd like to do is make an HTTP request to ~/content/test.json and download its contents, but the path is not found.
I've tried using Url.Content to map a relative path to the absolute path, but it doesn't work.
var url = Url.Content("~/content/test.json"); // spits out "/content/test.json"
I've DI'd IWebHostEnvironment into the controller and tried to access the ContentRootFileProvider and the ContentRootPath and WebRootPath, but those paths aren't right either. They are pointing to my currently running service's wwwroot's parent and wwwroot, respectively.
I've tried creating my own file provider:
var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, "resources");
var content = filesProvider.GetDirectoryContents("content");
var fileInfo = filesProvider.GetFileInfo(Path.Combine("content", "test.json"));
This successfully finds the file and claims it exists, but the fileInfo's PhysicalPath is always null.
I just want to do something like this:
string SomeMagicMapFunction(string s) => ????
var webClient = new WebClient();
var json = webClient.DownloadString(SomeMagicMapFunction("~/content/test.json"));
Where am I going wrong? Any pointers are appreciated.

What's the recommended way to load an internal file on the web site?

We've got a certain image in the \Images folder of our web site. We need to include that image in an OpenXml file we're generating internally, and for that we're using the following snippet:
var logo = Server.MapPath(#"~\Images\logo-new.png");
var imagePart = mainPart.AddImagePart(ImagePartType.Png); // mainPart is of type MainDocumentPart
using (var stream = new FileStream(logo, FileMode.Open))
{
imagePart.FeedData(stream);
}
Then later imagePart is used for embedding in the document.
This code works fine in development, but in deployment we're getting a System.UnauthorizedAccessException when we try to open the file for streaming.
Clearly there is an access permission problem, since Server.MapPath() is converting the web path to an absolute path on the server drive, and the IIS user doesn't have rights to that. We might be able to get around it by granting access to everyone, but something tells me that this is not the textbook way of doing it. Surely there must be a way of accessing this file that doesn't require us to start futzing with access permissions to the web deployment folder?
Solved, by including the file as a resource rather than by trying to access it through the file system:
var logo = Resources.logo_new;
var imagePart = mainPart.AddImagePart(ImagePartType.Png);
using (var stream = logo.ToStream(ImageFormat.Png))
{
imagePart.FeedData(stream);
}
Hat tip to this answer for the .ToStream() extension.

Using MVC 3 to dynamically create Site.css on IIS 6. Works in dev, prod fails. Why?

I am using an MVC controller/action to dynamically create the site.css in my MVC 3 site. The way it works is I map a route to Site.css like so:
routes.MapRoute("CSS", "Content/Site.css", new { controller = "CSS", action = "Index" });
Then in my CSSController I have the following code:
public ActionResult Index() {
string path = Request.PhysicalPath.Replace("Site.css","SiteStyles.css");
byte[] data = null;
try {
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
data = ProcessCSS(fs);
}
} catch (Exception e) {
Logger.Write(new LogEntry(e.Message, "Error", 99, 1001, System.Diagnostics.TraceEventType.Error, "CSS Error", null));
throw e;
}
return File(data, "text/css","Site.css");
}
What's going on in the ProcessCSS method is it's going through SiteStyles.css and performing a find/replace on some constants I have defined, so that I can have a set of colors defined at the top as named constants, then anywhere I need that color in the site I just use the named constant. That way I can change the color once, and it propagates to all of the appropriate places in the stylesheet without me having to go touch 5-6 different places.
The above code works great debugging in my local environment and on the dev server, which is Windows Server 2003 running IIS6. However, when I deploy it to a production server that is also Windows Server 2003 running IIS6 the css is not being loaded and when I try to browse to Site.css (which should be getting mapped via my route) I get a 404 not found error. If I go to my dev server and get the output for Site.css and create a physical Site.css file on the production server, it works.
Any idea why this is failing on the production server?
I added some logging to my CSSControler to log where it is looking for SiteStyles.css and the log simply isn't being generated on the production server, which tells me the server is ignoring the mapped route entirely and not executing the code in the Controller.
Any suggestions on where to start are appreciated.
Sounds to me like you should double-check your IIS configuration on the production server to make sure that the necessary mappings are applied.
Are you using a wildcard (star) mapping in IIS on your development server, or did you define a mapping for the .css extension? You may need to verify that the production server has the same mapping.
Try to add write rights to the folder your css is located in to the user that your pool is run under.

Why does my WebClient request work differently depending on it's hosting solution?

In it's very basic form I have a WebClient request for some xml in a Page.xaml code behind. Something like:
public Page()
{
InitializeComponent();
Uri uri = new Uri("Dummy.xml", UriKind.Relative);
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(uri);
}
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
//Do something
}
}
If I setup my Silverlight project to run through an asp.net hosted page, and then put Dummy.xml in the ClientBin folder (relative to the xap) it works fine.
If I setup the project using just the automatically generated test page option, and again put the xml relative to the xap, the request doesn't work (although the completed event does fire).
My question is why? Is it a requirement that any Silverlight project that dynamically downloads has to be on a server?
Cheers
J
First up, try to avoid using the auto generated test page. It requires you to understand how the silverlight security by default model works when the xap is being accessed as a file.
To answer your question, you're encountering the security designed to prevent unauthorised cross-domain access.
Yes, there is no webserver for it to connect to! The autogenerated test page just opens that XAP directly without invoking Visual Studio's web server. If you want to do this you must use the other option to create a website with the silverlight project. Alternatively, you can embed the XML file in the XAP as a resource and access it as a resource.

Resources