MVC Blank JsonResult - asp.net-mvc

I'm returning a JsonResult as part of an Orchard CMS Site (MVC 4) and it suddenly stopped working (specifics below).
Here is an example from my controller:
public JsonResult GetStartDate()
{
//a previous version of this question was different here
var startDate = _Settings.DateOpen.GetValueOrDefault(DateTime.MaxValue);
if (startDate < DateTime.Now)
startDate = DateTime.Now;
var start = new
{
year = startDate.Time.Year,
month = (startDate.Time.Month - 1)
};
return Json(start, JsonRequestBehavior.AllowGet);
}
It should be returning actual data. I have verified that the action is being hit and that "start" contains the correct data before being passed into the Json method.
If I navigate directly to the URL, I get a blank white screen.
Inspecting the result of an AJAX request shows that the call fails, the response body is an empty string , the status is "parsererror" and the actual error throws is "SyntaxError: Unexpected end of input."
POST requests work for some reason, this issue only applies to GETs.
This problem is with all JSON GETs, not just any specific method.
What could be affecting the data between the Json method and the client receiving the response?

By default all MVC methods are cached. This can lead to issues during the change/debug cycle. For starters you can turn off caching during development using the decorator below.
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult MyMethod()
You may want to wrap all methods with a caching scheme that is defined in the web.config. This allows caching to be controlled via one configuration change which comes in handy during development.
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear />
<add varyByParam="*" duration="0" name="MyCachePlan" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>
And use the following decorator:
[OutputCache(CacheProfile = "MyCachePlan")]
public ActionResult MyMethod()

Related

Blocked Webhook

I have a messaging webhook setup in Twilio that does a post to a URL on a server on Azure in the format https://******.*****corps.org:441/SMS The controller has been tested using NGrok locally and works great, in Azure when I use the get by typing in the URL I am able to get a response from the web server no problem, but the post from Twilio gets a 11200 retrieval failure. Is there something that would block the cross domain post on IIS that I am unaware of?
''' public class SMSController : TwilioController
{
[HttpPost]
public TwiMLResult Index(SmsRequest request)
{
var response = new MessagingResponse();
UserProfile _userProfileFrom = UserProfileService.GetByTwilioFromPhone(request.From);
...
return TwiML(response);
}
[HttpGet]
public ActionResult Index() //works fine..
{
return View();
}
}'''
Thanks for the edit Shoaib K. I found the problem using Postman (database connectivity error in my code). I was able to create a manual post and setting the following in the Web.config file (ASP.NET):
<compilation debug="true" targetFramework="4.7.2" />
<customErrors mode="Off"></customErrors>```

DonutOutputCache not working for an image

I have an ASP.NET MVC controller action like the following:
[HttpGet]
[DonutOutputCache(CacheProfile = "banner")]
public async Task<ActionResult> Banner(string name, string size = "lg")
{
// snipped - work out which banner to show today.
return File(thePathToSomeBannerImageFile, "image/jpeg");
}
And the configuration file looks like:
<caching>
<outputCacheSettings>
<outputCacheProfiles>
...
<add name="banner" duration="31536000" varyByParam="*" />
...
</outputCacheProfiles>
</outputCacheSettings>
</caching>
Since adding DonutOutputCache the image that I used to render to my browser now won't load. I can see in the Fiddler trace that a largish binary file is getting to the browser, but I can't seem to get it to render.
Removing the DonutOutputCache makes the image appear again.
I've tried clearing the cache etc. Any ideas?
Ah, just figured it out from this link: Doesn't work w/ Files?.
Basically DonutOutputCache uses ContentResult internally which works only with text-based content. Since I'm returning a binary response in a FileResult it messes stuff up. Fortunately it works side-by-side with the built in OutputCache, so I could modify my action as follows and it works as expected. I really only needed DonutOutputCache for other bits of my site that are text-based. I tripped myself up trying to just have one caching attribute to rule them all.
[HttpGet]
[OutputCache(CacheProfile = "banner")]
public async Task<ActionResult> Banner(string name, string size = "lg")
{
}

Why doesn't my action method time out?

I have the following controllers:
[TimeoutFilter]
public abstract class BaseController: Controller
{
}
public class IntegrationTestController : BaseController
{
[HttpGet]
public ActionResult TimeoutSeconds()
{
return Content(HttpContext.Server.ScriptTimeout.ToString(CultureInfo.InvariantCulture));
}
[HttpGet]
public ActionResult ForceTimeout()
{
var timeoutWindow = TimeoutFilter.TimeoutSeconds;
Thread.Sleep((timeoutWindow + 5) * 1000);
return Content("This should never get returned, mwahahaaa!");
}
}
For my test scenario I use a config setting of 5 seconds in the TimeoutFilter, and I know this is working because when my test calls TimeoutSeconds, I get the correct value of 5, but when the test calls ForceTimeout, I get an HTTP response of 200 and my 'never returned' text.
And the filter:
public class TimeoutFilter : ActionFilterAttribute
{
internal const string TimeoutSecondsSettingsKey = "MvcActionTimeoutSeconds";
internal static int TimeoutSeconds;
public TimeoutFilter()
{
TimeoutSeconds = int.Parse(ConfigurationManager.AppSettings[TimeoutSecondsSettingsKey]);
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ControllerContext.HttpContext.Server.ScriptTimeout = TimeoutSeconds;
base.OnActionExecuting(filterContext);
}
}
I could not get this to work by setting the ScriptTimeout property either, even when setting the debug="false" in the web.config as suggested by user Erik Funkenbusch:
<configuration>
<system.web>
<compilation debug="false" targetFramework="4.5"/>
...
It continued to return the text "This should never get returned" rather than timing out during the Thread.Sleep.
It is also worth noting that I also extended the Thread.Sleep to well beyond the Server.ScriptTimeout default of 110 seconds but it still eventually returned the same text rather than timing out.
I then instead tried to set executionTimeout in the web.config:
<configuration>
<system.web>
<httpRuntime targetFramework="4.5" executionTimeout="5"/>
...
If you were to now add a breakpoint to the TimeoutFilter you will observe that the ScriptTimeout value has been set to the executionTimeout value from web.config. Alas, this still did not work for me (regardless of whether debug="false").
I then came across this link about ScriptTimeout and executionTimeout not working with a similar setup to what you describe. The first reply in the post describes using the debug="false" and also mentions that the timeout will have a delay of 5 to 15 seconds. I still had no luck even when using a large Thread.Sleep value. The second reply in this article suggests that the executionTimeout config setting is a replacement of the ScriptTimeout property (which is apparently a COM interface used in classic ASP). This reply suggests that is not possible to set a specific timeout without using your own time-out logic.
Further, I then came across the following (more recent) link where the first reply suggests that the timeout is switched off in MVC. A further reply suggests that this is because an MVCHandler (which selects the controller that will handle the HTTPRequest) is an IHttpAsyncHandler and as it may therefore be executing another request (which is the point of using an async request) it therefore internally switches the time-out state off (this is what I gather from reading this link). It must work with straight asp.net though as using ScriptTimeout seems to be the accepted way in this answer.
The link suggests that adding the following line will allow it to work (but not in a medium trust application):
System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1);
Therefore, changing the TimeoutFilter OnActionExecuting() to:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1);
base.OnActionExecuting(filterContext);
}
and setting the web.config:
<configuration>
<system.web>
<compilation debug="false" targetFramework="4.5"/>
<httpRuntime targetFramework="4.5" executionTimeout="5"/>
...
allows the time-out to work but has the slight 5 second delay that is mentioned in the first post.
Note: Using this method does not allow you to set the ScriptTimeout property in the filter. Trying to set ScriptTimeout and override the value set in web.config does not appear to work.
Are you using a debug build?
From the ScriptTimeout documentation:
http://msdn.microsoft.com/en-us/library/system.web.httpserverutility.scripttimeout(v=vs.110).aspx
If you set the debug attribute of the compilation element to true in the Web.config file, the value of ScriptTimeout will be ignored.
Also, since this value is the same as that set on the httpRuntime element, I really don't understand the point of this, since you can just configure that setting in in your web.config instead.
Edit:
Dangerous has done a good job of finding out the details, and indeed, ScriptTimeout is unsupported in asynchronous pipelines (which MVC has been since at least MVC4 I think, as well as WebApi.. even if not using async methods)
The "workaround" as suggested by this connect report:
https://connect.microsoft.com/VisualStudio/feedback/details/781171/asp-net-mvc-executiontimeout-does-not-work
Use the [AsyncTimeout] attribute, and take a cancelation token as a parameter, then call CanclationToken.ThrowIfCancelationRequested periodically, or use the cancellation token in an async method.
Here's an example:
[AsyncTimeout(5000)]
public async Task<ContentResult> Index(CancellationToken ct)
{
await Task.Delay(10 * 1000, ct);
return Content("This should never get returned, mwahahaaa!");
}
This throws an OperationCanceled exception with a YSOD after 5 seconds. The bonus for this is that it works even in Debug mode ;)

Can not set Session variables in MVC 3

I know that my question is basic one yet i need some responses because i have tried many solutions on the net and i still get the some error.
I have a gridPanel in the first view. If i click a button in this view, the selected rows will be displayed in another view. I need to send information with these rows to the server so i can load some extra data in the action proper to the click button.
To perform that, i should use Session instead of TempData or ViewBag/ViewData because i don't know when the user will click the button. Please correct me if i'm mistaken.
My code is like that: In the client side with AJAX i call an action method to set the session variables:
Ext.Ajax.request({ url: 'Examples/SetSelectedStations', params: { selectedStations: stationsStr} });
in the SetSelectedStations controller i realised that Session["slectedStations"] is always null and acts like have never been set. this is my controller action:
public ViewResult SetSelectedStations(string selectedStations)
{
Session["slectedStations"] = selectedStations;
string ss = Session["slectedStations"] as string;
// Here ss is null !!!!!!
return View();
}
Should i define Session["slectedStations"] in other place? Is there a special configuration in the web.confg file?
Please notice that the sessionState in my web.config is like that:
<sessionState mode="Custom" customProvider="PgSessionStateStoreProvider">
<providers>
<clear />
<add name="PgSessionStateStoreProvider" type="NauckIT.PostgreSQLProvider.PgSessionStateStoreProvider" enableExpiredSessionAutoDeletion="true" expiredSessionAutoDeletionInterval="1800000" enableSessionExpireCallback="false" connectionStringName="AspSQLProvider" applicationName="WebSite1" />
</providers>
</sessionState>

Why is the HttpContext.Cache count always zero?

I set up a few pages with OutputCache profiles and confirmed that they are being cached by using multiple browsers and requests to retrieve the page with a timestamp which matched across all requests. When I try to enumerate the HttpContect.Cache it is always empty.
Any ideas what is going on here or where I should be going for this information instead?
Update:
It's not client cache because multiple browsers are seeing the same response. Here is a bit of code to explain what's happening.
Web.Config caching settings
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear/>
<add name="StaticContent" duration="1200" varyByParam="none"/>
<add name="VaryByParam" duration="1200" varyByParam="*"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
...
</system.web>
**Action Method With Caching
[OutputCache(CacheProfile = "StaticContent")]
public ActionResult Index()
{
return View(new CollaborateModel());
}
Code to enumerate the cache, yep it's rough, an this is defined in a controller action method
var sb = new StringBuilder();
foreach (KeyValuePair<string, object> item in HttpContext.Cache)
{
sb.AppendFormat("{0} : {1}<br />", item.Key, item.Value.ToString());
}
ViewData.Add("CacheContents", sb.ToString());
The HttpContext.Cache is where the count is always null, even though the cache seems to be working fine.
That's probably because the page has been cached downstream on the client browser and not on the server.
Instead of using the HttpCache I ended up rolling my own caching model for holding datasets in my Data Access layer. If I was looking up the AD profile of a given username and converting it to a DTO then I just put that profile in a rolling collection of profile DTOs that I would check before polling AD for the information.

Resources