CSS file only loads in IE when fetched via an ASP.NET MVC Controler + Action - asp.net-mvc

I'm serving up a site's CSS content via an ASP.NET MVC's Controller + Action. The css "file" appears to deliver correctly down the wire but only IE will apply it. Other browsers (Firefox, Opera, Chrome) ignore the CSS file and render the page without styling. IE8 works perfectly.
This is the essential code that I'm using to return the CSS via the controller and action:
public void CSS(string version)
{
string cssFile = Server.MapPath("/site.css");
string cssContents = System.IO.File.ReadAllText(cssFile);
Response.Write(cssContents);
}
Note that the version can be any string. I have tried with strings such as "myversion.css", "1.css", "1234", "arbitrary" etc.
The all work in IE8 but not in any other browser. Any ideas?

You'll have to send the proper Content-type: text/css header.
Firefox will ignore the style sheet otherwise, and output a warning in its error console. Same goes probably for the other Gecko/Webkit based browsers.

This was one of those cases where after typing out the question and pondering how to phrase it and then posting it the answer dawned on me. When I returned here Pekka had correctly answered the question. If anybody's interested here's some code that fixes the problem:
string fileLocation = Request.PhysicalApplicationPath + #"site.css";
ContentResult fcr = new ContentResult();
fcr.Content = System.IO.File.ReadAllText(fileLocation);
fcr.ContentType = "text/css";
return fcr;

Related

MVC - FileContentResult sends corrupted pdf

I have a simple action method that returns a PDF document, that gets shown in an <iframe> with an <embed> tag, and every few calls to this method will return a corrupted PDF. (I've determined its corrupted by using dev tools to save the response from the server)
Action Method:
public FileContentResult GetPdfReport(string Id)
{
Response.AppendHeader("Content-Disposition", "inline; filename=report.pdf");
var content = System.IO.File.ReadAllBytes(Server.MapPath("~/Reports/Testfile.pdf"));
System.IO.File.WriteAllBytes(Server.MapPath("~/Reports/debugReport.pdf"), content);
return File(content, "application/pdf");
}
View Content:
<embed id="widgetResponsePdf" src="#Url.Action("GetPdfReport", "WidgetResponse", new { Id = "123" })" type="application/pdf" onmouseout="mouseOutHandler();" />
The files TestFile.pdf and debugReport.pdf open just fine when I get a corrupted PDF, and there is no difference in the request and response header between the normal request/response and the corrupted request/response.
Is there some setting in IIS that I am missing that could be causing the inconsistent behavior between requests, or could this be caused solely by a network issue?
In our case, the IFrame has a src attribute that points to a partial view that loads the <embed> content, which then has a src attribute that points to the actual PDF file instead of a PartialView that returns a FileContentResult. The example below has been simplified from our actual implementation
Partial View
<iframe> <!-- iframe is actually loaded from another partial view, it is show here to simplify things -->
<embed
src='#Url.Content(Model.ReportFileName)'
type="application/pdf">
</embed>
</iframe>
Controller
public PartialView GetPdfReport(string Id)
{
var model = PDFResponseModel
{
ReportFileName = Server.MapPath("~/Reports/Testfile.pdf")
};
return PartialView(model);
}
Due to a site restriction for IE support, our users (intranet site) are required to have AdobeAcrobat installed to view PDF's. While this solution works for us, this may not be desirable for internet facing websites.

ASP.Net MVC 3 WebFormsViewEngine HTML Helpers and JSON data

I would like to know if is possible in ASP.Net MVC 3, using Web forms view engine and HTML Helpers, and the client side we are using Ext.Js to generate the grids.
The problem is when I return JSON(data) for the Ext.JS grid and the HTML Helper.
The HTML Helper is not able to render the JSON element.
It pops-up a window asking "What firefox should do with this file?".
I've tried to use:
return this.Json(new { objectJson = object}, "text/html", JsonRequestBehavior.AllowGet);
And it returned a new page with the HMTML Code, didn't bind to the HTML Helpers. I also tried without the JsonRequestBehavior.AllowGet and the result was:
This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.
And even if I change the MIME type of the Header to application/json and make the method's return as JSONResult instead of ActionResult it still doesn't recognize the file.
return this.Json(new { IssueInventoryPartModel = issueInventoryPartmodel, success = true }, "application/json", JsonRequestBehavior.AllowGet);
Briefly the question is: The HTML Helper for Web Form View Engine binds with JSON?
Best regards,
Tito
I had this problem while sending html data via json, and solved it by adding contenttype to the jsonresult, in the server side action method (called via js in client side), there should be something like :
return Json(dataToReturn, "text/html")
it sounds like the content-type for the action result is not being set properly
how about including JsonRequestBehavior.AllowGet on the return of the JSON as in:
return Json(new
{
data = components,
success = true
}, JsonRequestBehavior.AllowGet);

Struts2 how to create multiple views for mobile and desktop

I am creating a site which will be accessible via mobile and desktop devices. So I want to create 2 views of my application. My action code and everything else in the backend (manageers, DAOs) is same. Just JSP changes for both.
How I can do this via Struts 2?
In struts there are many way to obtain the same thing.
In this case, the one I prefer is:
You could write an interceptor that changes the return code based on the user-agent of
the client, such that there would be versions for PC and mobile of each jsp.
In your configuration you need to have all the result codes for all jsp (or you could simply define the result through the wildcard mapping).
For example: change the result code from "success" to "mobile_success". In case you want map both results in the same jsp you can map, as I said before, in this way
<result name="*success">
not sure whether there is library for automating such task for struts 2. but if there is, using such libraries might be better
anyway, here is the theory. every browser has its own "signature" written in the request header, called "User-Agent". different browser (supposedly) has different user agent. for example, my firefox user agent is as following:
Mozilla/5.0 (Windows NT 6.0; rv:5.0) Gecko/20100101 Firefox/5.0 FirePHP/0.5
basically, by detecting the user agent, you can know what browser is used to access your site. the list of mobile browser user agents can be found in http://www.zytrax.com/tech/web/mobile_ids.html
if i'm not wrong, you can retrieve the user agent in server by httpServletRequest.getHeader("User-Agent"); (correct me if i'm wrong)
you can then create an interceptor which will decide whether a client is from mobile or from desktop. that interceptor can return different result for different client type. for example, if the client is desktop, you can return "successDesktop" and if the client is mobile, you can return "successMobile".
well, hopefully someone else can come up with (far) easier solution
I am currently trying to solve this very same problem. A framework would be nice, and I'm all ears if anyone has tested and approved one. That said, I can't find anything mature enough for me to be justify moving from Struts for the mobile view.
My best solution currently is to create actions for each of the parts of my full page which will be displayed on full browsers. Then to reuse those actions to display page segments on the mobile side.
I found trying to make one page look right for a desktop browser and a mobile browser simultaneously was not a sustainable approach.
jQuery mobile looks like a very promising library for styling the elements retrieved by struts.
So while it is surely possible to cram both versions of the site into one action I think taking the time to create small reusable actions that result in jsp snippits will pay off as your app scales.
Here are some possibilities for the near future:
(I can't add these as links as I don't have enough reputation...you'll have to add the 'http://www.')
Struts2 jQuery Mobile Project homepage: http://code.google.com/p/struts2-jquery/
Struts2 jQuery Mobile project: code.google.com/p/struts2-jquery/downloads/detail?name=struts2-jquery-mobile-showcase-3.1.1.war
an example of struts2 jQuery Mobile: weinfreund.de/struts2-jquery-mobile-showcase/index.action
#fajrian - using 'user agent' to determine a browser type could become a real pain as more and more mobile and desktop browsers are released. A better approach would be to determine whether to display a mobile version or full version based on the window's dimensions. A perfect example.
edit - Check out CSS3 media queries.
As Maurizio said you could use interceptors. Here is what I found.... http://www.benmccann.com/blog/struts-2-tutorial-interceptors/
This works for me and should basically get round the problem. You do need to know at least part of the user agent strings though:
public class MobileInterceptor extends AbstractInterceptor {
private static final String RESULT_CODE_SUFFIX_MOBILE = "mobile";
private static final String REQUEST_HEADER_ACCEPT = "Accept";
private static final String[] MOBILE_BROWSER_UAS = {"iPhone OS","Android","BlackBerry","Windows Phone"};
public String intercept(ActionInvocation invocation) throws Exception {
invocation.addPreResultListener(new PreResultListener() {
public void beforeResult(ActionInvocation invocation, String resultCode) {
// check if a wireless version of the page exists
// by looking for a wireless action mapping in the struts.xml
Map results = invocation.getProxy().getConfig().getResults();
System.out.println("Results:"+results.toString());
if(!results.containsKey(resultCode + RESULT_CODE_SUFFIX_MOBILE)) {
return;
}
// send to mobile version if mobile browser is used
final String acceptHeader = ServletActionContext.getRequest().getHeader(REQUEST_HEADER_ACCEPT);
//Get User Agent String
String userAgent = ServletActionContext.getRequest().getHeader("User-Agent");
System.out.println("UA: "+userAgent);
//Boolean to indicate whether to show mobile version
boolean showMobileVersion = false;
//Run through each entry in the list of browsers
for(String ua : MOBILE_BROWSER_UAS){
if(userAgent.toLowerCase().matches(".*"+ua.toLowerCase()+".*")){
showMobileVersion = true;
}
}
if(showMobileVersion) {
invocation.setResultCode(resultCode + RESULT_CODE_SUFFIX_MOBILE);
}
}
});
return invocation.invoke();
}

Hash navigation problem while using jquery mobile with asp.net mvc2

I am looking to standardize the processing of ajax #anchors at the server side, using MVC.
Before a controller action is invoked I want to convert every request with ajax anchors into a request without ajax anchors, so that the controller code does not know there were anchors in the request:
For example:
1) /user/profile#user/photos should be treated as /user/photos
2) /main/index#user/profile/33 should be treated as /user/profile/33
What is the best technique in MVC to accomplish that?
This should necessarily be done on the client side, probably using jquery as everything that follows the # sign is never sent to the server.
I too struggle with same issue and I solved this problem after looking at Visual Studio 11 Developer Preview template code. I added following code in my _layout.cshtml, please note we must load jquery.mobile*.js file after following script tag:
<script type="text/javascript">
$(document).bind("mobileinit", function () {
// As of Beta 2, jQuery Mobile's Ajax navigation does not work in all cases (e.g.,
// when navigating from a mobile to a non-mobile page, or when clicking "back"
// after a form post), hence disabling it. http://jquerymobile.com/demos/1.0a3/#docs/api/globalconfig.html
#{
if (ViewBag.JqueryMobileAjaxEnabled != null && ViewBag.JqueryMobileAjaxEnabled == true)
{
#: $.mobile.ajaxEnabled = true;
}
else
{
#: $.mobile.ajaxEnabled = false;
}
}
});
</script>
**<script src="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js"></script>**

What is the correct response to an HTTP POST request?

For a POST method, the W3 specs say:
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see Section 10.4).
http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p2-semantics-05.txt (section 8.5)
The standard response actually seems to be to send a Redirect to the newly created resource.
I'm building my site with ASP.NET MVC, and tried to follow the spec, so created a ResourceCreatedResult class:
public class ResourceCreatedResult : ActionResult
{
public string Location { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.StatusCode = 201;
context.HttpContext.Response.ClearHeaders();
context.HttpContext.Response.AddHeader("Location", Location);
}
}
And my action looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateNew(string entityStuff)
{
Entity newEntity = new Entity(entityStuff);
IEntityRepository entityRepository = ObjectFactory.GetInstance<IEntityRepository>();
entityRepository.Add(newEntity);
ActionResult result = new ResourceCreatedResult()
{ Location = Url.Action("Show", new { id = newEntity.Id }) };
return result;
}
However, IE, Firefox and Chrome all fail to redirect to the new resource. Have I messed up generating the correct response, or do web browsers not expect this type of response, instead relying on servers to send a Redirect response?
To be explicit, browsers (including modern browsers like Firefox 3 and IE8) do not "take the hint" and follow up an HTTP 201: Created response with a GET request to the URI supplied in the Location header.
If you want browsers to go to the URI supplied in the Location header, you should send an HTTP 303: See Other status instead.
Redirect after post or post/redirect/get is something your application must do to be user friendly.
Edit. This is above and beyond the HTTP specifications. If we simply return a 201 after a POST, the browser back button behaves badly.
Note that Web Services requests (which do NOT respond to a browser) follow the standard completely and do NOT redirect after post.
It works like this.
The browser POSTS the data.
Your application validates the data. If it's invalid, you respond with the form so they can fix it and POST.
Your application responds with a redirect.
The browser gets the redirect and does a GET.
Your application sees the GET and responds.
Now -- hey presto! -- the back button works.
My solution is to respond with a '201 Created' containing a simple page with a link to the new resource, and a javascript redirect using location.replace().
This lets the same code work for API and browser requests, plays nicely with Back and Refresh buttons, and degrades gracefully in old browsers.
As stated in the spec the response SHOULD be a HTTP 201 with redirect. So it isn't mandatory for a browser vendor to implement the correct answer...
You should try to change to a 30x code to see if it is correctly redirected. If so, it's a browser problem, else it may come from your code (I don't know anything in ASP.NET so I can't "validate" your code)
Shouldn't that only count for when something is "Created" and therefore a simple redirect to action should be genuinely sufficient?

Resources