I am implementing some custom Glimpse Tabs to show advanced statistics from our framework. So far that works great. The problem I could not fix so far is, that the tab content does not get updated after AJAX calls. In the debugger I see that GetData() gets called and returns the up to date stats but the Glimpse UI is still showing the old tab content.
Here is the simplest of my pages returning a plain object with a few prop in it (database command counter, etc. - nothing fancy).
public class GlimpseTabOverview : TabBase
{
public override string Name
{
get { return "Overview"; }
}
public override object GetData(ITabContext context)
{
if (context == null) { throw new ArgumentNullException("context"); }
return WebStatisticsHelper.GetBasicStatsData();
}
}
Refreshing the whole page does show the new values but not when doing Ajax. I took a look (or two) at the Glimpse source but could not yet find what could cause that.
We use ASP.Net MVC 5.1 with IIS-Express and the latest Glimpse and Glimpse.AspMvc5.
Does anybody have an idea why the Glimpse UI does not take the new data?
Are you selecting the Ajax request that occurred from the Ajax tab? The Glimpse context doesn't just change when an Ajax call occurs. Since these calls could happen very quickly or when you are trying to read the data of the origin request, we leave it up to you to decide when you view the ajax requests Glimpse data. To do this, simply go to the Ajax tab and when the request appears, select that request and view the relevant tab. Let em know if that fixes the issue you are having.
Related
Using a asp mvc system, I would like to perform some kind of user notification that a record was added into the database.
Current paradigm... navPage -> modPage -> datagridPage -> newDatabasePage -> (record added action) This is where it stops, the user is not notified that record is added or failure, it simply reloads the view.
Currently - i am using some text in a viewbag variable after the record was added and based on this value, display a simple javascript message box. But I think there is a better way.
Was thinking that a modal popup implemented through jquery would accomplish this task, but i was educated this was not an optimal solution without using a messaging framework (signalR etc).
Another approach was to use an additional partial page - another partial page????
Any different options that i have missed here would be greatly appreciated.
You can add some beautiful notifications using sweetalert2, here is the documentation
Are you using Bootstrap (or similar)?
Can you not just pass some information into a hidden-as-default alert div?
Assuming you're using EF, when you save an object you can capture the new Id so you can just check for this.
Instead of reloading the view, redirect to the action that creates the initial view and change it so you can pass in the new Id:
int newId = _context.SaveChanges();
return RedirectToAction("GridView", new { Id = newId });
Then change the signature of the Action:
public async Task<ActionResult> GridView(int? Id)
You can then just check if the Id has a value and do something with that information. Then just add that to the ViewModel for the page and display the alert if required:
if (Id.HasValue)
{
viewModel.displayAlert = true;
}
If you don't want to reload the view in full then you can accomplish the same thing using Ajax calls.
I have an ASP.NET MVC 4 application that has one section that behaves like a SPA. It's a page with multiple steps and, because I'm working sessionless, I'm sending from the client to the server (using AJAX) the ID of the entity in every request (I'm also sending a GUID that needs to correspond to the ID in order to be valid, this is for detecting data tampering). Let's say that the user is on step 3 and one of the following things happen:
1) An error occurs: I have a global filter that inherits from HandleErrorAttribute that logs the error and sends an email, and after all, it shows a custom error page. The problem is that if the user press the browser's back button, the hidden fields are lost and the process has to start from step 1 again.
2) The user navigates away from the page. I think that I can warn the user with a dialog.
Thanks in advance.
EDIT:
I'm showing a warning dialog when the user wants to navigate away.
$(window).bind('beforeunload', function () {
if ($("#id").val() != "") {
return 'If you leave the page, the offer will be lost.';
}
});
If after he navigates away presses the browser's back button, I'm redirecting him to the first step of the flow because the previous entered data is lost.
if ($("#id").val() == "" && window.location.hash != "") {
window.location.hash = "";
}
It sounds like your AJAX request for the next step is hitting a Controller action that's redirecting you to a new page. That's fine, and it's good you're keeping your server code stateless by sending up all the relevant information back up to the Controller for each step. However, doing it this way means that you're stuck using the custom error page, and you're going to have trouble making that work well with your setup.
My suggestion: move more towards a true SPA. When I visit Step1, the Controller should send back a whole page (like you're doing). Let's assume that this page has a container like <div id="step-container"> ... HTML for each step is in here ... </div>.
Now, when you click the button to move on to step 2, instead of hitting the controller action expecting to get redirected to a new page, send out an AJAX request for a Partial View with the Step 2 content.
On the server, change your Step2.cshtml from a regular view to a Partial View (you can make a new View and click the Partial View checkbox), and for convention's sake, you should probably rename it _Step2.cshtml. In your Controller action public ActionResult Step2(... data), you could change your return statement to return PartialView("_Step2"), but leaving it as return View("_Step2") is just fine.
Now for the important part, the client. Here, you're issuing an AJAX request for that Partial View.
// Set the data from your form in this variable
var data = { };
// Issue a GET request out to the controller action. Make sure the URL is right
$.get('/Steps/Step2', data)
.done(function(result) {
// This promise will execute when we get the content of the Partial View back from the server
// The result variable should have the HTML for the view
// Use jQuery to set the content in your step div to the new HTML
$('#step-container').html(result);
})
.fail(function(error) {
// This promise function will execute if there is an error in the Controller
// and it returns something other than a 200 type response code
// Handle the error here, maybe showing a dialog or trying to fix the error
alert('Sorry, form submission failed');
});
I have an ASP.NET MVC web app and have a function that I need to call when the page loads only once. Right now I have the function being called from a base controller OnActionExecuted.
The issue I'm having is that this function is called multiple times - once for the page, and then multiple times for different ajax calls that I have on the page. I've tried putting the function on Controller Initialize but this is also called for each ajax call to a controller action. So is there some function in the ASP.NET MVC page cycle that only gets called when a page is requested (GET) and not for all of the ajax calls (POST)? The only thing I can think of is putting all of the ajax calls in separate controllers that don't inherit from the base controller but there must be a nicer solution.
Depending on how you're doing your AjaxRequests you could use something like the following:
public ActionResult Index()
{
if (!Request.IsAjaxRequest())
{
LoadConfiguration();
}
// Rest of Action method (snip)...
}
This works if, for instance, you're performing Ajax with the jQuery JavaScript library which sends a special token to the server to indicate that it's an Ajax call (I'm sure other libraries do this). This might be better just in case someone changes the JavaScript code to perform GET Ajax requests.
One thing you mentioned does intrigue me though "The issue I'm having is that this function is called multiple times" - actually 'technically' this is not true. It IS only getting called once....per request, all those Ajax calls are treated as separate requests by the server, as if the user is requesting a page via the web browser. It sounds like what you really need is a way to differentiate between web page HTTP Requests, and Ajax HTTP Requests, hence the above solution.
It came to me right after posting the question...
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
if (Request.HttpMethod == "GET")
{
LoadConfiguration();
}
}
You can either do this work in the application scope (on start, in global.asax or other similar approaches), or store a configuration object in the session (or a flag to identify it has already been done, if there is nothing to store).
Since upgrading from mvc 2 beta 2 to rc I'm having trouble with an ajax submission in Internet Explorer. Upon carrying out a jquery form post, the function returns a url to a controller action. This worked fine with the controller action picking up it was a ajaxrequest and then piping back a partial view to update the page. This still works fine in Firefox, however in Internet Explorer the final call to the controller action now comes from cache and returns therefore returns a full view rather than partial.
I've tried setting the outputcache to 0 with no success and I've also tried the nocache actionfilter as described here Disable browser cache for entire ASP.NET website with no luck. The only way I can stop IE from pulling from cache is to physically delete the cached version.
Anyone have any ideas (apologies if this isn't very clear, tricky one to explain!)?
For some reason, IE is really aggressive about caching AJAX GETs. So if you are fetching that via AJAX, the behavior is not surprising to me. Also not surprising is that using output cache attribute didn't fix the problem, because it is IE, rather than the server, which is doing the caching. What you need to do is to tell IE not to cache the request, by setting the appropriate headers in the HTTP. Here is how we do it:
[CacheControl(HttpCacheability.NoCache), HttpGet]
public JsonResult DoStuff()
{
//...
}
public class CacheControlAttribute : ActionFilterAttribute
{
public CacheControlAttribute(HttpCacheability cacheability)
{
this._cacheability = cacheability;
}
private HttpCacheability _cacheability;
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
cache.SetCacheability(_cacheability);
}
}
My 2 cents to Craig's great solution -
If you're using a user control and rendering it using an "RenderAction"
<% Html.RenderAction("UserList", "User"); %>
And this page invokes it via GET as well as POST then don't mention the request method in the attribute declaration.
[CacheControl(HttpCacheability.NoCache)]
For example, I've a search Grid and a search panel on top of it. I've made my Grid a user-control so that I can invoke the sort & paging via AJAX (GET) still it is also invoked when I press the "search" button (POST) so I need it for both.
I have a Product controller with Index action, which basically creates the view form for post and Index (Post action verb) action on the ProductController which basically save the product to db but when validation errors occur, I am returning a View(mymodel) else when saved, I am returning RedirectToAction("Created,"Product") but for some odd reason when I break into the code , it is hitting the Product Controller action twice rather than just once. Hence the product has 2 records instead of one.
public ActionResult Index()
{
return View()
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
// 2 calls are made to this controller
try
{
// save the product
return RedirectToAction("Created");
}
catch(Exception ex)
{
// recreate the model from form collection
return View(viewData); // when a validation error occurs it comes into the catch block
}
}
Sometimes I have found Firebug to cause this behavior. Try disabling its Script panel, if you have it installed.
Explanation: In some cases Firebug isn't able to get the script sources for the display within its Script panel. In these cases it initiates a second request to get them. See issue 7401 for some discussion about this, which alleviates the problem and is fixed with Firebug 2.0.2.
Here's a basic checklist (copied from here):
Check that you don’t have any image or another elements in the View with an
empty src attribute (<img src=”" /> for example) or have src
attribute referencing something that no longer exists. You better
check directly in the browser's “Page Source”, than in the View itself due to the
possibility of some “dynamic” issues when the View is rendered. Once you
find such empty element in the page's HTML source its usually trivial to
find the same element in your View and fix the issue. This can also happen with <link href="">.
Check that you don’t have any AJAX calls referencing an empty URL (browsers will interpret such empty URL as the current page and will request the current page again making the Controller action execute few times).
You forgot to return “false” from the JavaScript click event handler for a link or button that makes an AJAX call. If you forget to “return false”, the browser simply interprets the default action of the link – regular, non AJAX, calling the same page again)
Sometimes Firebug and YSlow [ Firefox (FF) plugins ] can cause such issues. Just temporarily disable them in FF or test with a different browser.
Watch out for duplicate filters decorating your controller or action. (this was my problem)
Another solution for this case..
I had exactly same problem, running and testing from Chrome. I couldn't debug it because the second call was coming from (external call). I have randomly tested it in Firefox and Internet Explorer where there was no double hit.
Whatever nasty thing it was, I have deleted Chrome cache (everything!!!) and problem has been resolved.
Hope it will help some of you :)
I had a similar issue with a controller action that generated an image, and I was only seeing it with Firefox. There is a really old bug that causes this, that I guess is still there.
https://bugzilla.mozilla.org/show_bug.cgi?id=304574