How to access built in UI for Mini Profiler and without Cassette throwing InvalidDataException regarding GZip header? - mvc-mini-profiler

I am trying to access the built-in UI for Mini Profiler, but it either does nothing or Cassette gets in the way throwing an exception.
With Cassette url rewriting enabled, I encounter this error when browsing to "~/mini-profiler-resources/results-index":
[InvalidDataException: The magic number in GZip header is not correct. Make sure you are passing in a GZip stream.]
System.IO.Compression.GZipDecoder.ReadHeader(InputBuffer input) +8662842
System.IO.Compression.Inflater.Decode() +560
System.IO.Compression.Inflater.Inflate(Byte[] bytes, Int32 offset, Int32 length) +118
System.IO.Compression.DeflateStream.Read(Byte[] array, Int32 offset, Int32 count) +85
System.IO.Compression.GZipStream.Read(Byte[] array, Int32 offset, Int32 count) +33
System.IO.Stream.InternalCopyTo(Stream destination, Int32 bufferSize) +62
Cassette.Aspnet.PlaceholderReplacingResponseFilter.WriteCompressedOutput(Func`3 createCompressionStream) +136
Cassette.Aspnet.PlaceholderReplacingResponseFilter.Close() +24
System.Web.HttpWriter.FilterIntegrated(Boolean finalFiltering, IIS7WorkerRequest wr) +12599767
System.Web.HttpResponse.FilterOutput() +121
System.Web.CallFilterExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +119
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
I don't have any other compression services running (which could be a problem if it was in place and url rewriting was enabled). If I disable url rewriting in Cassette, there is no error and I see this in the emitted HTML, but nothing is displayed:
<html><head>
<title>List of profiling sessions</title>
<script id='mini-profiler' data-ids='' type='text/javascript' src='/mini-profiler-resources/includes.js?v=kpfJeIOqwihzCDVVKMPIcBwCBaKk3jhX5Le1VL+KMf4='></script>
<link href='/mini-profiler-resources/includes.css?v=kpfJeIOqwihzCDVVKMPIcBwCBaKk3jhX5Le1VL+KMf4=' rel='stylesheet' type='text/css'>
<script type='text/javascript'>MiniProfiler.list.init({path: '/mini-profiler-resources/', version: 'kpfJeIOqwihzCDVVKMPIcBwCBaKk3jhX5Le1VL+KMf4='})</script>
</head><body></body></html>
I am pretty certain it has to do with how MiniProfiler needs to render includes and something Cassette is doing isn't compatible with MiniProfiler.
I am using SqlServerStorage and so I can see timings emitted to the database and I can see the popup timings UI on any given page. Here is my initialization done in Application_Start():
MiniProfiler.Settings.Storage = new SqlServerStorage(ConfigurationManager.ConnectionStrings[Shared.Constants.ConnectionStrings.MiniProfiler].ConnectionString);
MiniProfilerEF.Initialize();
MiniProfiler.Settings.PopupStartHidden = true;
MiniProfiler.Settings.Results_Authorize = httpRequest => true;
MiniProfiler.Settings.Results_List_Authorize = httpRequest => true;
I tried added this to web.config in the right place:
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
I am using the following package versions:
MiniProfiler.3.0.10-beta6
MiniProfiler.EF5.3.0.10-beta1
MiniProfiler.Mvc4.3.0.10-beta1
Platform is .NET, C#, MVC4, ASP.NET, IIS7, etc.
Any ideas on what might be wrong with my setup or what is going on with Cassette? It might be obvious as I am new to MiniProfiler.
Thanks for any insights!

A bit late on this but I believe the issue stems from cassette's html rewriting. Adding <cassette debug="true" rewriteHtml="false"/> into the Web.config solved the issue for me.

Related

altering ember baseURL at deploy- or runtime

I'm a back end dev working on a project which includes an ember front end. Our project is unusual in that we have no production access; we write the code and deliver to client. The client is only comfortable/willing to use the Microsoft web stack, so we build the ember project, wrap the resulting contents into a simple Visual Studio project, and hand it over for deployment.
This client has unfortunately put us in a position that is apparently unusual in the ember world:
Client is unwilling to install or execute any of the ember-cli tools or commands
Client uses different directory structures for test and production sites (i.e. "http://staging.example.com/project" vs. "http://project.example.com/")
To honor the above requirements, we have been shipping separate builds for the two different environments. But this is also considered unacceptable in the long term.
Obviously, this is a situation that no one would have chosen with perfect foresight. Most of these restrictions were not made explicit until it was too late, but realistically the client will not be changing them. I am looking for a technical solution that looks like this:
We develop in ember
We use ember-cli tools (or equivalent) to build front-end
We package results into one visual studio project, which may include web.config for client's test environments
Zip up and deliver to client
Based on settings in web.config, our ember project configures itself to:
set baseURL to appropriate value
connect to our REST API located at environment-specific URL
In order to solve the problem, I have been reviewing the following:
https://github.com/ember-cli/ember-cli/issues/417
http://www.ember-cli.com/user-guide/#deployments
using baseUrl affects the path to my assets
Unfortunately, I am personally unfamiliar with ember. So I don't understand how baseURL is really used yet, and why it seems to be so awkward to parameterize ember at deploy- or runtime. Where can I go to learn how to mash our work into an acceptable deployment process?
Is it possible to send values for baseURL or ourBackendApiURL to ember by putting META tags onto the index.html that loads the site?
You can get rid of baseURL by setting baseURL: null in your environment.js. This will prevent ember-cli from generating a base tag. Also, if you are using location hash for urls (http://example.com/index.html#/path-to-route), I suggest to set locationType: 'hash' in environment.js. With default settings you will have problems if ember app located not in web-server's root directory.
Then when it was explained that the un-communicated requirements are really obstructive and will require additional man-hours, they of course understand you need to bill that out? ;)
You can try just adding this:
<base href="project">
It should be automatically picked up. Otherwise in app.js you can override the baseURL and rootURL property:
var Router = Ember.Router.extend({
location: 'history',
rootURL: function(){
return "/random/";
}.property(),
baseURL: function(){
return "/more-random/";
}.property()
});
I would consider going with something like ember-cli-dotenv so you can specify your baseURL at build/runtime. All they need to do is either specify BASE_URL=https://whatever-they-want.crazyclient.com in a .env file in the root of the project (ignored from version control), or to specify BASE_URL in the actual environment. This allows you and them to use the server you choose.
ember-cli implementation:
// Brocfile.js or ember-cli-build.js:
var app = new EmberApp({
dotEnv: {
clientAllowedKeys: ['ROOT_URL', 'BASE_URL']
}
});
// pre-generated config from ember-cli
module.exports = app.toTree();
And then:
// config/environment.js
module.exports = function(environment){
return {
ROOT_URL: process.env.ROOT_URL,
BASE_URL: process.env.BASE_URL,
}
};
Finally:
var Router = Ember.Router.extend({
location: 'history',
rootURL: function(){
return ENV['ROOT_URL'] || 'somedefault';
}.property(),
baseURL: function(){
return ENV['BASE_URL'] || 'someotherdefault';
}.property()
});
Here's what ultimately solved it. Basically, we took the index.html which was created by "ember build", and found the meta tag which was passing in the values from environment.js to our javascript at runtime. By generating that meta tag in index.cshtml, we were able to use values specified in web.config.
Now when we build the app to hand off, we simply ignore the index.html that it generates, but add the rest of the assets to a pre-made visual studio web project. That project may be configured for testing or production.
First, I created an empty web application in visual studio. In web.config, I added this:
<appSettings>
<add key="hostName" value="https://apps.example.com/" />
<add key="baseURL" value="/projectDir/" />
<add key="serverNamespace" value="api" />
<add key="imgSrc" value="https://images.example.com" />
</appSettings>
and then index.cshtml was written to make use of those values:
#{
if (!Request.Url.AbsoluteUri.EndsWith("/"))
{
Response.Redirect(Request.Url.AbsoluteUri + "/");
}
var configStr = #"{{
""modulePrefix"": ""foo-bar"",
""podModulePrefix"": ""foo-bar/pods"",
""environment"": ""production"",
""baseURL"": ""{3}"",
""locationType"": ""hash"",
""namespace"": ""{0}"",
""host"": ""{1}"",
""foo-auth-host"": ""{1}"",
""APP"": {{
""name"": ""foo-bar"",
""version"": ""0.0.0""
}},
""contentSecurityPolicy"": {{
""default-src"": ""'none'"",
""script-src"": ""'self'"",
""font-src"": ""'self'"",
""img-src"": ""'self' {2}"",
""style-src"": ""'self'"",
""media-src"": ""'self'"",
""connect-src"": ""'self' {1}""
}},
""simple-auth"": {{
""authorizer"": ""authorizer:foo"",
""routeAfterAuthentication"": ""/"",
""store"": ""simple-auth-session-store:local-storage""
}},
""contentSecurityPolicyHeader"": ""Content-Security-Policy-Report-Only"",
""exportApplicationGlobal"": false
}}";
var serverNamespace = System.Web.Configuration.WebConfigurationManager.AppSettings["serverNamespace"];
var hostName = System.Web.Configuration.WebConfigurationManager.AppSettings["hostName"];
var imgSrc = System.Web.Configuration.WebConfigurationManager.AppSettings["imgSrc"];
var baseUrl = System.Web.Configuration.WebConfigurationManager.AppSettings["baseURL"];
var configStrPopulated = string.Format(configStr, serverNamespace, hostName, imgSrc, baseUrl);
var configStrCompacted = System.Text.RegularExpressions.Regex.Replace(configStrPopulated, #"\s+", "");
var configStrEncoded = HttpUtility.UrlEncode(configStrCompacted);
}<!DOCTYPE html>
<html>
<head>
...
<meta name="foo-bar/config/environment" content="#configStrEncoded" />
...
</head>
<body>
<script src="assets/vendor.js"></script>
<script src="assets/foo-bar.js"></script>
</body>
</html>

JSF AJAX and normal redirect to login and back to previous page

Current status :
If any session time out occurs, redirectToLogin function in FacesAjaxAwareUserFilter will be executed. From there I can redirect to any page I need. I get the URI in all cases.
It's all working fine and big thanks to BalusC. :)
Now the second part which makes the issue
Redirect to login and come back to the previous page.
For Eg :
Page 5----> Login------> Page 5
I have appended the redirect URI to the login URI and retrieved the values from the bean.
But the problem is that I have 2 pages before the user login. A login mode selection page (ie; google authentication or default login) and the page that reads the username and password.
How can I pass the redirect URI through both the pages.?
This is the code I have used to redirect at Ajax time out and in normal session time out.
Class FacesAjaxAwareUserFilter
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
res.setContentType("text/xml");
res.setCharacterEncoding("UTF-8");
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() + getLoginUrl()+"?redirectUrlPattern="+request.getRequestURI());
}
else {
if (request.getRequestedSessionId()!=null && (!SecurityUtils.getSubject().isAuthenticated() || !request.isRequestedSessionIdValid())) {
response.sendRedirect(getLoginUrl()+"?redirectUrlPattern="+request.getRequestURI());
return;
}
super.redirectToLogin(req, res);
}
Method used is FullAjaxExceptionHandlerFactory in Omniface.
I have used a method of appending the values to the URI, but it fails to identify whether the session is expired or a session not created (when a user logs in at first).
Problem Code
if (request.getRequestedSessionId()!=null && (!SecurityUtils.getSubject().isAuthenticated() || !request.isRequestedSessionIdValid()))
I am looking for a way to identify the expired session from new session created before login.
Wish to implement this in a Better Way.
A method which will not append present URI with the redirect URL is most welcomed.
I have founded out a solution but still i don't find it as the best solution. Any other answer for doing it is greatly appreciated.
Step 1
Configure the application to detect Ajax Timeout and normal timeout. This is how i did it..!!
Step 2
Finding the URI when session timeout occurs, using this.
FacesAjaxAwareUserFilter will grab the ServletRequest and ServletResponse for you.
form that you can convert that to HttpServletRequest and HttpServletResponse using this
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) res;
The request.getRequestURI() will get you the redirect URI
String redirectURI=request.getRequestURI();
Now you want to save this to some storage so that you can use it in any place you want. The only way i found is to append it with URL using this.
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() + "/sessionexpired"+"?redirectUrlPattern="+request.getRequestURI());
or
response.sendRedirect("/sessionexpired"+"?redirectUrlPattern="+request.getRequestURI());
Now on the page load of my sessionExpiry page bean, i used this to grab the value passed through the URL
redirectUrl=FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("redirectUrlPattern");
Now using JavaScript i set that value of redirectUrl to localStorage. This is how you can save values to local storage.
This is my sessionexpiry.xhtml page.
<script type="text/javascript">
function setRedirectURIToLocalStorage(){
if(typeof(Storage)!=="undefined")
{
localStorage.redirectURI=document.getElementById("redirectUrl").value;
window.location.href="/login";
}
}
</script>
</h:head>
<h:body id="body" onload="setRedirectURIToLocalStorage()">
<f:view contentType="text/html">
<h:form prependId="false" >
<h:inputHidden id="redirectUrl" value="#{sessionExpBean.redirectUrl}" />
<h:outputText value="Session Expired... Redirecting...!!"></h:outputText>
</h:form>
</f:view>
</h:body>
The page will call setRedirectURIToLocalStorage() function onLoad
and then it set the values to the localStorage. Thus the redirect
value is available all across the browser. You can use that in any
page you need.!! All you need to do is to check in this variable
localStorage.redirectURI

jQuery ajax JSON response too big

I have a .NET web service that returns a string to a jQuery $.ajax call.
If the string's length is less than 88900 (or so) it works fine, but as soon as I add 100 more characters to the string, it does not work anymore. I get a 500 Internal Server error.
How can I resolve this issue?
jQuery doesn't limit the size, but ASP.NET does by default. You can adjust it with this web.config setting:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="x">
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
You can increase the max length of you Json result.
var list = Json(new { list = tasksList }, JsonRequestBehavior.AllowGet);
list.MaxJsonLength = int.MaxValue;

Ajax.ActionLink navigates away

I have an Ajax.ActionLink that successfully calls my controller action but instead of updating the target with the return value, it navigates to a new page and shows the return value.
I have the unobtrusive ajax script in my view
<script src="../../Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
And these scripts are in my layout page
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
Here is my action link:
<span id = "status">Account is Active</span>
#Ajax.ActionLink("Deactivate",
"Deactivate",
"Lender",
new {id = Model.ID},
new AjaxOptions {
HttpMethod = "GET",
Confirm = "Confirm Deactivation",
UpdateTargetId = "status"
})
My controller action:
public string Deactivate(int id) {
var status = "Account is Active";
... // call method to deactivate account
... // set status = "Account is Inactive"
return status;
}
The return value is correctly set. So why is the page navigating away instead of doing what Ajax is supposed to do, stay put?
You need to include the jquery.unobtrusive-ajax.min.js library to your page:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
Notice how I included it in my answer which is the correct way. And not like this:
<script src="../../Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
Never hardcode urls in an ASP.NET MVC application. Always use Url helpers.
Also make sure that unobtrusive ajax is enabled in your web.config:
<appSettings>
<add key="webpages:Version" value="1.0.0.0"/>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
Make sure you have removed absolutely all traces of Microsoft*.js scripts. Those are completely obsolete and should not be used at all.
Include MicrosoftMvcAjax.js with your list of scripts.
With regards to hearing it's no longer necessary, I'm not entirely sure how true that is, I've only found that when using the AjaxHelper extension methods, that file seems to make it all work out-of-the-box.
I did notice that MS's CDN doesn't show a MicrosoftMvcAjax.js file for MVC 4, so that may be the version that's switched to using purely jQuery, but I can't be entirely sure.

MVC3 app on IIS7.5 with route to file x.jpg not working

When my clean, just created new app (.net 4.0 integrated) is on Visual Studio Web Server everything works fine. Link like this below works fine and controller returns image.
http://localhost:12345/image/a.jpg
But when I run this app on IIS 7.5 then iis takes control and reports 404.
http://localhost/testmvc3/image/a.jpg
Controller:
public class ImageController : Controller
{
public ActionResult Index(string name)
{
var dir = Server.MapPath("~/content/" + name);
return File(dir, "image/jpg");
}
}
Routes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Image", // Route name
"image/{*name}", // URL with parameters
new { controller = "Image", action = "Index", name = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
What I should change to run this app properly?
EDIT1:
The problem is with extension. When I remove extension then requests points to image controller. With extension (jpg) iis takes request first (why!?) and returns 404 (without touching image controller action).
EDIT2:
IIS 7.5 on Windows 7 64bit
App on Framework 4.0 integrated pipeline
web.config before my changes:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
I found it. Uchh.....
I change ExtensionlessUrlHandler path from default '*.' to '*':
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add
name="ExtensionlessUrlHandler-Integrated-4.0"
path="*"
verb="GET,HEAD,POST,DEBUG"
type="System.Web.Handlers.TransferRequestHandler"
resourceType="Unspecified"
requireAccess="Script"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
Now all requests are going through routing engine.
Then I add a IgnoreRoute to 'content/{*all}' where I have all static content files.
If the solution is deployed, that is, not only mapped against your solution but instead deployed as it should be, the result of Server.MapPath will not be as you expect. The Server.MapPath "default" folder is where the actual dll is.
One way you can solve this on is to set the "Copy to Output Directory" for your images to "Copy alwats" or "Copy if newer".
You could maybe use something like Server.MapPath("~/content" + name);, but I that will make your solution not finding the images.
In the Properties for your project, on the Web tab, in the section below the radio button Use Local IIS Web Server, in the box for Project Url, change the entry to http://localhost:12345.
Then, in IIS, edit the http binding for the localhost site, and change it to 12345.
you should not be required to do that. Make sure your application pool is running in Integrated pipeline mode.

Resources