I'm starting to use Stackoverflow MiniProfiler on my ASP MVC 4 web application.
I've put only the Start and Stop calls in BeginRequest and EndRequest respectively.
I've add to one action some steps like so:
private ActionResult MyAction(string id)
{
using (MiniProfiler.Current.Step("GatherReportItems")) {
...
}
using (MiniProfiler.Current.Step("BuildReportViewModel")) {
...
}
using (MiniProfiler.Current.Step("AddingExtraInfo")) {
...
}
}
The problem is that on the first request to that action I can see all 3 steps, on any further request I see only the first step and not any of the others.
When I debug my application I can see inside MiniProfiler.Current -> Head -> Children that all the 3 steps are there. It is in the client display (after clicking on the timing box) that I can see only part of the steps.
I've now notice that there is a small link name show trivial at the bottom of the profiling details popup which add the very short timings
Related
There is a sort of "trick" that I've seen around more than once, in order to clear the cache for an MVC app by calling a specific url similar to
http://somewebsite.com/Misc/ClearCache
I used it a couple of times, but honestly I didn't understand exactly how it works and I haven't found any documentation or post about it.
Is there anyone that could explain it a bit, possibly with some related documentation?
Many thanks.
I am not sure if you are using some plugin or 3rd party library for that. But it is as simple as :
write a web method to clearcache like:
public void Clearcache()
{
HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
HttpContext.Current.Response.Cache.SetValidUntilExpires(false);
HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
}
Call method from browser with like controller/actionname :http://somewebsite.com/Controller/ClearCache
If cache is 3rd party you can delete as required in same method
I was wrong in my comment, no Ajax needed.
Here would be your JQuery:
$("#clearCache").click(function () {
if (!$(this).disabled) {
$('<iframe id="cacheCleared" src="../../Misc/ClearCache"></iframe>').appendTo('body').hide();
}
});
Then in your Misc Controller you would have:
public ActionResult ClearCache()
{
foreach (System.Collections.DictionaryEntry entry in HttpContext.Cache)
{
HttpContext.Cache.Remove((entry.Key).ToString());
}
return View();
}
Once you append your iframe, it will attempt to load the content from that source. When it tries to load that source, it will hit your ClearCache in your controller and should clear everything.
EDIT:
Add this before you return View(); if you want to avoid building a view for it.
System.Web.HttpContext.Current.Response.End();
I have a very established n-tiered ASP.NET MVC application that currently does everything synchronously; all controllers inherit from Controller rather than AsyncController.
What I want to do is to take one of the lower tiers (that literally every flow consumes) and put in an awaited call to a WCF. Why await? Well, I figure that it will reduce the overall thread-count and make the server more scalable.
However, I am not in a position to change any of the code outside of this tier. So normally, one would change the calling methods from returning T to return 'async Task', and give the method name an "async" suffix, e.g.:
from
public string GetData()
to
public Task<string> GetDataAsync()
Okay, so I went about it with the following (cut down) code:
public ResponseObject GetSomething(RequestObject request)
{
return MyMethodAsync(request).Result;
}
private static async Task<ResponseObject> MyMethodAsync(RequestObject request)
{
using (var client = new Client(new NetTcpBinding(), new EndpointAddress(Url))))
{
await client.DoSomething(request).ConfigureAwait(true);
}
}
When I run this code (F5), it gets to the line where it calls the "await client.DoSomething(request).ConfigureAwait(true);" and then, unfortunately, that's the last I see of my thread. Occassionally it does return when I'm debugging (F11), but 99% of the time it doesn't.
The non-ASYNC method works perfectly fine
Debugging the WCF service shows it receives the request, processes it and returns
Using a console app, this works perfectly. It's only when I try this in one of my "middle" tiers of my web application that the thread disappears.
I've tried with .ConfigureAwait(true) and .ConfigureAwait(false).
Short answer: don't block on async code (your problem's the .Result which blocks, while its Task is a concurrent one, not a parallel one)
Long answer (and really good reading, too): Don't Block on Async Code
When testing an ASP.NET MVC 2 application I hit a problem when a view could not be located.
Looking at the code I realised that the aspx file for the view had not been added to the source control repository. On this project that's quite easy to do as we use StarTeam for source control and it doesn't show new folders when checking in. This view was for a new controller and so a new folder was created for it and it was therefore missed.
Our build server (using Hudson/MSBuild) didn't pick up on this, as the code still builds fine with the aspx file missing. Our controller unit tests test the ActionResults which obviously still pass without the view there.
This got picked up in system testing but how can I catch this earlier (ideally on the build server).
Thanks in advance
You can write unit tests that test the actual view, and then if the unit test doesn't pass on the build server, you know you have a problem. To do this, you can use a framework such as this:
http://blog.stevensanderson.com/2009/06/11/integration-testing-your-aspnet-mvc-application/
With this you can write unit tests such as this (from the post)
[Test]
public void Root_Url_Renders_Index_View()
{
appHost.SimulateBrowsingSession(browsingSession => {
// Request the root URL
RequestResult result = browsingSession.ProcessRequest("/");
// You can make assertions about the ActionResult...
var viewResult = (ViewResult) result.ActionExecutedContext.Result;
Assert.AreEqual("Index", viewResult.ViewName);
Assert.AreEqual("Welcome to ASP.NET MVC!", viewResult.ViewData["Message"]);
// ... or you can make assertions about the rendered HTML
Assert.IsTrue(result.ResponseText.Contains("<!DOCTYPE html"));
});
}
What version of StarTeam are you running? In StarTeam 2008 (not sure when this feature was first added) within a selected project/view, you can select from the menu Folder Tree->Show Not-In-View Folders. This will show folders you have on local disk that have not been added to the project (they will appear with the folder icon colored white).
This is an old question, but if anyone still looking for this you ought to try SpecsFor.Mvc by Matt Honeycutt.
Not only it can be used to make sure the Views are properly included/added in the source control, it can even do integration test to make sure those Views are valid.
Link to its website: http://specsfor.com/SpecsForMvc/default.cshtml
Link to the nuget package: https://www.nuget.org/packages/SpecsFor.Mvc/
Link to github: https://github.com/MattHoneycutt/SpecsFor
Here is a code snippet taken from the website showing how to use it.
public class UserRegistrationSpecs
{
public class when_a_new_user_registers : SpecsFor<MvcWebApp>
{
protected override void Given()
{
SUT.NavigateTo<AccountController>(c => c.Register());
}
protected override void When()
{
SUT.FindFormFor<RegisterModel>()
.Field(m => m.Email).SetValueTo("test#user.com")
.Field(m => m.UserName).SetValueTo("Test User")
.Field(m => m.Password).SetValueTo("P#ssword!")
.Field(m => m.ConfirmPassword).SetValueTo("P#ssword!")
.Submit();
}
[Test]
public void then_it_redirects_to_the_home_page()
{
SUT.Route.ShouldMapTo<HomeController>(c => c.Index());
}
[Test]
public void then_it_sends_the_user_an_email()
{
SUT.Mailbox().MailMessages.Count().ShouldEqual(1);
}
[Test]
public void then_it_sends_to_the_right_address()
{
SUT.Mailbox().MailMessages[0].To[0].Address.ShouldEqual("test#user.com");
}
[Test]
public void then_it_comes_from_the_expected_address()
{
SUT.Mailbox().MailMessages[0].From.Address.ShouldEqual("registration#specsfor.com");
}
}
}
I have a few utility actions that return text output via return Content("my text","text/plain").
Sometimes these methods take a few minutes to run (i.e. log parsing, database maintenance).
I would like to modify my action method so that instead of returning all of the output at once, the text is instead streamed to the client when it is ready.
Here's a contrived example:
public ActionResult SlowText()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("This happens quickly...");
sb.AppendLine("Starting a slow 10 second process...");
System.Threading.Thread.Sleep(10000);
sb.AppendLine("All done with 10 second process!");
return Content(sb.ToString(), "text/plain");
}
As written, this action will return three lines of text after 10 seconds. What I want is a way to keep the response stream open, and return the first two lines immediately, and then the third line after 10 seconds.
I remember doing this 10+ years ago in Classic ASP 3.0 using the Response object. Is there an official, MVC-friendly way to accomplish this?
--
Update: using Razor .cshtml in the app; but not using any views (just ContentResult) for these actions.
Writing directly to the Response object should work, but only in some simple cases. Many MVC features depend on output writer substitution (e.g. partial views, Razor view engine, and others) and if you write directly to the Response your result will be out of order.
However, if you don't use a view and instead write straight in the controller then you should be fine (assuming your action is not being called as a child action).
I would skip the MVC controller entirely since you are going to break encapsulation anyway. In it's place I'd use a barenaked IHttpHandler implementation, streaming directly to the aforementioned output stream.
You are exposing yourself to a browser timeout if the process takes longer than originally intended. Then you don't have a way to recover what happened / unless you implement a separate method that gives the information on the long running process.
Given that you want the other method anyway, you can start a long running process and return immediately. Have the browser check the other method that gives the latest information on the long running process. On the last time I had to do this, I kept it simple and just set the refresh header from the controller before returning the view.
As for starting a long running process, you can do something like this:
// in the controller class
delegate void MyLongProcess();
//...
// in the method that starts the action
MyLongProcess processTask = new MyLongProcess(_someInstance.TheLongRunningImplementation);
processTask.BeginInvoke(new AsyncCallback(EndMyLongProcess), processTask);
//...
public void EndMyLongProcess(IAsyncResult result)
{
try{
MyLongProcess processTask = (MyLongProcess)result.AsyncState;
processTask.EndInvoke(result);
// anything you needed at the end of the process
} catch(Exception ex) {
// an error happened, make sure to log this
// as it won't hit the global.asax error handler
}
}
As for where do you put the log of the actions that happened, it's up to you to how long lived you want it to be. It can be as simple as a static field/class where you add the info of the ongoing process, or instead saving it to a data store where it can survive an application recycle.
The above assume this is all about a long running process that goes on reporting the actions that has been done. Streaming is a different subject, but the above might still play a role in keeping the operations in your controller & only the piece responsible of streaming what becomes available to the client in the action result.
You can implement your custom ActionResult like ContentStreamingResult and use HttpContext, HttpRequest and HttpResponse in the ExecuteResult method.
public class ContentStreamingResult : ActionResult
{
private readonly TextReader _reader;
public ContentStreamingResult(TextReader reader)
{
_reader = reader;
}
public override void ExecuteResult(ControllerContext context)
{
var httpContext = context.HttpContext;
//Read text from the reader and write to the response
}
}
public class YourController : Controller
{
public ContentStreamingResult DownloadText()
{
string text = "text text text";
return new ContentStreamingResult(new System.IO.StringReader(text));
}
}
Try Response.Flush and BufferOutput to false. Note it would work with the different action results, you have to directly write into the response object. Probably you can use it with conjunction with AsyncController.
I'm using ASP.NET MVC and have a long running process. Specifically I am generating a large PDF for the user to download.
I understand the basic concept:
Action method gets called
New thread started to generate process
Return a View that tells the user the (pdf) is being generated
Use AJAX to call the server and ask for progress
Once finished, present the file to the user for download.
The parts I don't fully understand are:
The management of the thread across separate AJAX calls. I will possibly need some way of finding the running thread and requesting a status. Is there a static context I can keep a reference to the thread in? I'm aware of the Data Caching in HttpContext.Application, would that be suitable for this?
And how to present the completed file. Do I create a temp file and present a download link? Or can I make a final AJAX call that returns the file?
It works!
Here's what I've done:
Step 1 & 2 - Action Method gets called, long running thread is started
When my action method gets called, it generates a unique ID. I then instantiate an instance of my PdfGenerator class, create a new thread that calls PdfGenerator.Generate and start it.
public class PdfGenerator
{
public string State;
public byte[] Data;
public void Generate()
{
// Generate PDF/Long running process
// Should update State as it goes
// ...
// Once finished, Data is populated with the binary byte[]
}
}
Once the thread has started (or before starting) the generator instance is stored in the cache:
HttpContext.Cache[guid] = generator;
I also attach the guid to the ViewData so that it can be reference in my view script.
Step 3 & 4 - Display and update status/progress view
Now that the thread is running and PDF generation has begun, I can display my progress view script. Using jQuery's $.getJSON I am able to poll a separate Action to find the status of the generation:
[OutputCache(Duration = 0, VaryByName = "none", NoStore = true)]
public JsonResult CheckPdfGenerationStatus(string guid)
{
// Get the generator from cache
var generator = HttpContext.Cache[guid] as PdfGenerator;
if (generator == null)
return Json(null);
else
return Json(generator.State);
}
My view script interprets the Json and displays the appropriate progress information.
Step 5 - Present file to user
Once the generation is completed, the generators state is set accordingly and when jQuery receives this information, it can either make available a link, or directly send the file using javascripts location.href.
The Action method that sets up and returns the file simply gets the generator out of the cache and returns the attached byte[]
public ContentResult DownloadPdf(string guid)
{
var generator = HttpContext.Cache[guid] as PdfGenerator;
if (generator == null)
return Content("Error");
if (generator.State == "Completed")
{
return Content(generator.Data);
}
else
{
return Content("Not finished yet");
}
}
My my actual work I've got more detailed state such as Initialised, Running and Completed. As well as a progress percentage (expressed as a decimal, 1.0 being complete).
So yeah, hope that helps anyone else trying to do something similar.
The Cashe is very well suitable for that. Only one thing is to make sure the item cached is never removed while the process is running (You can use ItemPriority.NotRemovable for that).
You can save the file on disk in a temp folder or you can keep it in cache for some time (it depends).
I personally don' like to pollute hard disk with files so I would keep the file in the cache (with MediumPriority for a couple of minutes). But if the file is large and can be generated often consider using a Database of file system instead.
On the client, when the last Ajax request returns result( can look like {progress: "100%", resultUrl: "http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE-KEY"} ) you can redirect the browser to a URL provided.
It, in turn, will render that file as a binary result.
Client redirect can be done using Javascript like this:
location.href = response.resultUrl;
BTW, how do you generate PDF? NFOP?