Aim: I have a url like http://localhost:55830/shop/116_news - among other things, the filter has the task to change url to http://localhost:55830/shop/news
I tried:
filterContext.RouteData.Values[ActionFilter.Value] = "/shop/" + StringHelper.RemoveDiacritics(value.Value.ToLower());
filterContext.ActionArguments[ActionFilter.Value] = "/shop/" + StringHelper.RemoveDiacritics(value.Value.ToLower());
filterContext.HttpContext.Request.Path = "/shop/" + StringHelper.RemoveDiacritics(value.Value.ToLower());
None of above change url during OnActionExecuting
Whole action filter class:
public class ValueUrlFilterAttribute : ActionFilterAttribute
{
private readonly IValueTypeRepository repositoryValueType;
public ValueUrlFilterAttribute(IValueTypeRepository repoValueType)
{
repositoryValueType = repoValueType;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string v = filterContext.RouteData.Values[ActionFilter.Value] as string;
List<string> vInfo = ActionFilter.GetList(v);
int valueId = ActionFilter.GetValueId(vInfo);
string valueName = ActionFilter.GetValueName(vInfo);
ValueType value = repositoryValueType.GetValueByValueId(valueId);
if (value.Value.ToLower() == valueName)
{
object param;
filterContext.RouteData.Values[ActionFilter.Value] = "/shop/" + StringHelper.RemoveDiacritics(value.Value.ToLower());
filterContext.ActionArguments[ActionFilter.Value] = "/shop/" + StringHelper.RemoveDiacritics(value.Value.ToLower());
filterContext.HttpContext.Request.Path = "/shop/" + StringHelper.RemoveDiacritics(value.Value.ToLower());
if (filterContext.ActionArguments.TryGetValue("value", out param))
{
filterContext.ActionArguments["value"] = value;
}
base.OnActionExecuting(filterContext);
}
}
}
I don't want to redirect to another action, I want to go to the action that I originally called
PS Sending new argument filterContext.ActionArguments["value"] = value; works great!
Issue I don't know how to change http://localhost:55830/shop/116_news to http://localhost:55830/shop/news
Thanks!
Just use the RouteAttribute con your action method:
[Route("shop/news")]
public IActionResult AnythingHere()
{
return View();
}
If you need to remove 116 from multiple urls consider makeing a global template in Startup.cs more info here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.1
If you want to change the URL in the browser then it's not possible without a redirect.
I am trying to display date in dd-MM-yyyy but the date i am getting is always in this format:
2016-08-08T16:17:40.643
I am using asp.net mvc and returning data in json format but displaying this date with angular js.
Here is the answer i am trying from the Link and i have combined the answer given by Perishable Dave and dav_i:
public class JsonNetFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is JsonResult == false)
{
return;
}
filterContext.Result = new JsonNetResult(
(JsonResult)filterContext.Result);
}
private class JsonNetResult : JsonResult
{
private const string _dateFormat = "dd-MM-yyyy";
public JsonNetResult(JsonResult jsonResult)
{
this.ContentEncoding = jsonResult.ContentEncoding;
this.ContentType = jsonResult.ContentType;
this.Data = jsonResult.Data;
this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
this.MaxJsonLength = jsonResult.MaxJsonLength;
this.RecursionLimit = jsonResult.RecursionLimit;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var isMethodGet = string.Equals(
context.HttpContext.Request.HttpMethod,
"GET",
StringComparison.OrdinalIgnoreCase);
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& isMethodGet)
{
throw new InvalidOperationException(
"GET not allowed! Change JsonRequestBehavior to AllowGet.");
}
var response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType)
? "application/json"
: this.ContentType;
if (this.ContentEncoding != null)
{
response.ContentEncoding = this.ContentEncoding;
}
if (this.Data != null)
{
// Using Json.NET serializer
var isoConvert = new IsoDateTimeConverter();
isoConvert.DateTimeFormat = _dateFormat;
response.Write(JsonConvert.SerializeObject(this.Data));
}
}
}
}
[JsonNetFilter]
public ActionResult GetJson()
{
return Json(new { hello = new Date(2016-08-02 05:49:11.000) }, JsonRequestBehavior.AllowGet)
}
How to date in dd-MM-yyyy format??
You're not passing your isoConvert variable to JsonConvert.SerializeObject(this.Data), so it's never used. You need to pass it to SerializeObject using an appropriate overload:
response.Write(JsonConvert.SerializeObject(this.Data, new [] { isoConvert } ));
I am trying to return the current dynamic View to allow me to append a css class to an ActionLink if the current View is the same as the ActionLink.
As I am passing the majority of links through a specific route, in this case Pages, the currentAction will always be Pages in most cases, despite the actual View or Template being returned from the ActionResult called.
So for example if the url is http://mytestdomain.com/sport I would like the currentAction to be Sport and not Pages.
Please see my code below:
RouteConfig.cs
routes.MapRoute("Pages", "{mainCategory}/{subCategory}/{pageName}", new { controller = "Home", action = "Pages", subCategory = UrlParameter.Optional, pageName = UrlParameter.Optional });
HomeController
public static MvcHtmlString MenuLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName)
{
var currentController = htmlHelper.ViewContext.ParentActionViewContext.RouteData.GetRequiredString("controller");
var currentAction = htmlHelper.ViewContext.ParentActionViewContext.RouteData.GetRequiredString("action");
var currentView = htmlHelper.CurrentViewName();
var builder = new TagBuilder("li")
{
InnerHtml = htmlHelper.ActionLink(linkText, actionName, controllerName).ToHtmlString()
};
builder.AddCssClass("dropdown");
var actionSplit = actionName.TrimStart('/').Split('/');
actionName = actionSplit[0];
if (controllerName == currentController && actionName == currentAction)
{
return new MvcHtmlString(builder.ToString().Replace("a href", "a class=\"active\" href").Replace("</li>", "").Replace("Home/", ""));
}
return new MvcHtmlString(builder.ToString().Replace("</li>", "").Replace("Home/", ""));
}
public static string CurrentViewName(this HtmlHelper html)
{
return System.IO.Path.GetFileNameWithoutExtension(((RazorView)html.ViewContext.View).ViewPath);
}
public ActionResult Pages(string mainCategory, string subCategory, string pageName)
{
if (!string.IsNullOrEmpty(pageName))
{
subCategory = subCategory + "/" + pageName;
}
Page model;
using (CMSEntities)
{
model = (from f in CMSEntities.GetPage(1, mainCategory, subCategory, "Live") select f).FirstOrDefault();
}
return View(model.Template, model);
}
Navigation.cshtml
#Html.MenuLink(navigation.Title, "/" + Html.ToFriendlyUrl(navigation.Title), "Home")
I have tried using var currentView = htmlHelper.CurrentViewName(); but this will always return Navigation as the ActionLink is being called from within a [ChildActionOnly] public ActionResult Navigation() for example #{ Html.RenderAction("Navigation", "Home"); } from within Views/Shared/_Layout.cshtml
Any help would be much appreciated :-)
In the end I used 'HttpContext.Current.Request.Url.AbsolutePath' to determine the current location to append the active class to the matching page link.
public static MvcHtmlString MenuLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName)
{
var currentController = htmlHelper.ViewContext.ParentActionViewContext.RouteData.GetRequiredString("controller");
var currentUrl = HttpContext.Current.Request.Url.AbsolutePath.TrimStart('/').Split('/');
var mainCategory = currentUrl[0];
var builder = new TagBuilder("li")
{
InnerHtml = htmlHelper.ActionLink(linkText, actionName, controllerName).ToHtmlString()
};
builder.AddCssClass("dropdown");
var actionSplit = actionName.TrimStart('/').Split('/');
actionName = actionSplit[0];
if (actionSplit.Length == 1)
{
if (controllerName == currentController && actionName == mainCategory)
{
return new MvcHtmlString(builder.ToString().Replace("a href", "a class=\"active\" href").Replace("</li>", "").Replace("Home/", ""));
}
}
return new MvcHtmlString(builder.ToString().Replace("</li>", "").Replace("Home/", ""));
}
I hope this proves useful to others :-)
In one of my controller actions I am returning a very large JsonResult to fill a grid.
I am getting the following InvalidOperationException exception:
Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
Setting the maxJsonLength property in the web.config to a higher value unfortunately does not show any effect.
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483644"/>
</webServices>
</scripting>
</system.web.extensions>
I don't want to pass it back as a string as mentioned in this SO answer.
In my research I came across this blog post where writing an own ActionResult (e.g. LargeJsonResult : JsonResult) is recommended to bypass this behaviour.
Is this then the only solution?
Is this a bug in ASP.NET MVC?
Am I missing something?
Any help would be most appreciated.
It appears this has been fixed in MVC4.
You can do this, which worked well for me:
public ActionResult SomeControllerAction()
{
var jsonResult = Json(veryLargeCollection, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
You could also use ContentResult as suggested here instead of subclassing JsonResult.
var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };
return new ContentResult()
{
Content = serializer.Serialize(data),
ContentType = "application/json",
};
Unfortunately the web.config setting is ignored by the default JsonResult implementation. So I guess you will need to implement a custom json result to overcome this issue.
No need for a custom class. This is all that is needed:
return new JsonResult { Data = Result, MaxJsonLength = Int32.MaxValue };
where Result is that data you wish to serialize.
I'm surprised no one has suggested using a result filter. This is the cleanest way to globally hook into the action/result pipeline:
public class JsonResultFilter : IResultFilter
{
public int? MaxJsonLength { get; set; }
public int? RecursionLimit { get; set; }
public void OnResultExecuting(ResultExecutingContext filterContext)
{
if (filterContext.Result is JsonResult jsonResult)
{
// override properties only if they're not set
jsonResult.MaxJsonLength = jsonResult.MaxJsonLength ?? MaxJsonLength;
jsonResult.RecursionLimit = jsonResult.RecursionLimit ?? RecursionLimit;
}
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
}
}
Then, register an instance of that class using GlobalFilters.Filters:
GlobalFilters.Filters.Add(new JsonResultFilter { MaxJsonLength = int.MaxValue });
If use Json.NET to generate the json string, it doesn't need to set MaxJsonLength value.
return new ContentResult()
{
Content = Newtonsoft.Json.JsonConvert.SerializeObject(data),
ContentType = "application/json",
};
Alternative ASP.NET MVC 5 Fix:
In my case the error was occurring during the request. Best approach in my scenario is modifying the actual JsonValueProviderFactory which applies the fix to the global project and can be done by editing the global.cs file as such.
JsonValueProviderConfig.Config(ValueProviderFactories.Factories);
add a web.config entry:
<add key="aspnet:MaxJsonLength" value="20971520" />
and then create the two following classes
public class JsonValueProviderConfig
{
public static void Config(ValueProviderFactoryCollection factories)
{
var jsonProviderFactory = factories.OfType<JsonValueProviderFactory>().Single();
factories.Remove(jsonProviderFactory);
factories.Add(new CustomJsonValueProviderFactory());
}
}
This is basically an exact copy of the default implementation found in System.Web.Mvc but with the addition of a configurable web.config appsetting value aspnet:MaxJsonLength.
public class CustomJsonValueProviderFactory : ValueProviderFactory
{
/// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
/// <returns>A JSON value-provider object for the specified controller context.</returns>
/// <param name="controllerContext">The controller context.</param>
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
object deserializedObject = CustomJsonValueProviderFactory.GetDeserializedObject(controllerContext);
if (deserializedObject == null)
return null;
Dictionary<string, object> strs = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
CustomJsonValueProviderFactory.AddToBackingStore(new CustomJsonValueProviderFactory.EntryLimitedDictionary(strs), string.Empty, deserializedObject);
return new DictionaryValueProvider<object>(strs, CultureInfo.CurrentCulture);
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return null;
string fullStreamString = (new StreamReader(controllerContext.HttpContext.Request.InputStream)).ReadToEnd();
if (string.IsNullOrEmpty(fullStreamString))
return null;
var serializer = new JavaScriptSerializer()
{
MaxJsonLength = CustomJsonValueProviderFactory.GetMaxJsonLength()
};
return serializer.DeserializeObject(fullStreamString);
}
private static void AddToBackingStore(EntryLimitedDictionary backingStore, string prefix, object value)
{
IDictionary<string, object> strs = value as IDictionary<string, object>;
if (strs != null)
{
foreach (KeyValuePair<string, object> keyValuePair in strs)
CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);
return;
}
IList lists = value as IList;
if (lists == null)
{
backingStore.Add(prefix, value);
return;
}
for (int i = 0; i < lists.Count; i++)
{
CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakeArrayKey(prefix, i), lists[i]);
}
}
private class EntryLimitedDictionary
{
private static int _maximumDepth;
private readonly IDictionary<string, object> _innerDictionary;
private int _itemCount;
static EntryLimitedDictionary()
{
_maximumDepth = CustomJsonValueProviderFactory.GetMaximumDepth();
}
public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
{
this._innerDictionary = innerDictionary;
}
public void Add(string key, object value)
{
int num = this._itemCount + 1;
this._itemCount = num;
if (num > _maximumDepth)
{
throw new InvalidOperationException("The length of the string exceeds the value set on the maxJsonLength property.");
}
this._innerDictionary.Add(key, value);
}
}
private static string MakeArrayKey(string prefix, int index)
{
return string.Concat(prefix, "[", index.ToString(CultureInfo.InvariantCulture), "]");
}
private static string MakePropertyKey(string prefix, string propertyName)
{
if (string.IsNullOrEmpty(prefix))
{
return propertyName;
}
return string.Concat(prefix, ".", propertyName);
}
private static int GetMaximumDepth()
{
int num;
NameValueCollection appSettings = ConfigurationManager.AppSettings;
if (appSettings != null)
{
string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
{
return num;
}
}
return 1000;
}
private static int GetMaxJsonLength()
{
int num;
NameValueCollection appSettings = ConfigurationManager.AppSettings;
if (appSettings != null)
{
string[] values = appSettings.GetValues("aspnet:MaxJsonLength");
if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
{
return num;
}
}
return 1000;
}
}
I solved the issue by following this link
namespace System.Web.Mvc
{
public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return null;
var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
var bodyText = reader.ReadToEnd();
return String.IsNullOrEmpty(bodyText) ? null : new DictionaryValueProvider<object>(JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new ExpandoObjectConverter()), CultureInfo.CurrentCulture);
}
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
//Remove and JsonValueProviderFactory and add JsonDotNetValueProviderFactory
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory());
}
there is a bit other case - data is sent from client to server.
when you are using controller method and model is huge :
[HttpPost]
public ActionResult AddOrUpdateConsumerFile(FileMetaDataModelView inputModel)
{
if (inputModel == null) return null;
....
}
system throws exception like this "Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property. Parameter name: input"
Only changing Web.config settings is not enough to help in this case. You could additionally override mvc json serializer for supporting huge data model sizes or manually deserialize model from Request. Your controller method becomes:
[HttpPost]
public ActionResult AddOrUpdateConsumerFile()
{
FileMetaDataModelView inputModel = RequestManager.GetModelFromJsonRequest<FileMetaDataModelView>(HttpContext.Request);
if (inputModel == null) return null;
......
}
public static T GetModelFromJsonRequest<T>(HttpRequestBase request)
{
string result = "";
using (Stream req = request.InputStream)
{
req.Seek(0, System.IO.SeekOrigin.Begin);
result = new StreamReader(req).ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(result);
}
You can try define in your LINQ expression only the field's that you will need.
Example. Imagine that you have an Model with Id, Name, Phone and Picture (byte array) and need to load from json into an select list.
LINQ Query:
var listItems = (from u in Users where u.name.Contains(term) select u).ToList();
The problem here is "select u" that get all fields. So, if you have big pictures, booomm.
How to solve? very, very simple.
var listItems = (from u in Users where u.name.Contains(term) select new {u.Id, u.Name}).ToList();
The best practices is select only the field that you will use.
Remember. This is a simple tip, but can help many ASP.NET MVC developpers.
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonResult()
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior,
MaxJsonLength = Int32.MaxValue
};
}
Was the fix for me in MVC 4.
None of the above worked out for me until I changed the Action as [HttpPost].
and made the ajax type as POST.
[HttpPost]
public JsonResult GetSelectedSignalData(string signal1,...)
{
JsonResult result = new JsonResult();
var signalData = GetTheData();
try
{
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };
result.Data = serializer.Serialize(signalData);
return Json(result, JsonRequestBehavior.AllowGet);
..
..
...
}
And the ajax call as
$.ajax({
type: "POST",
url: some_url,
data: JSON.stringify({ signal1: signal1,.. }),
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data !== null) {
setValue();
}
},
failure: function (data) {
$('#errMessage').text("Error...");
},
error: function (data) {
$('#errMessage').text("Error...");
}
});
You need to read from the configuration section manually before your code returns a JsonResult object. Simply read from web.config in single line:
var jsonResult = Json(resultsForAjaxUI);
jsonResult.MaxJsonLength = (ConfigurationManager.GetSection("system.web.extensions/scripting/webServices/jsonSerialization") as System.Web.Configuration.ScriptingJsonSerializationSection).MaxJsonLength;
return jsonResult;
Be sure you defined configuration element in web.config
this worked for me
JsonSerializerSettings json = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var result = JsonConvert.SerializeObject(list, Formatting.Indented, json);
return new JsonResult { Data = result, MaxJsonLength = int.MaxValue };
You can put this code in cshtml if you are returning view from controller and you want to increase the length of view bag data while encoding in json in cshtml
#{
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
jss.MaxJsonLength = Int32.MaxValue;
var userInfoJson = jss.Serialize(ViewBag.ActionObj);
}
var dataJsonOnActionGrid1 = #Html.Raw(userInfoJson);
Now, dataJsonOnActionGrid1 will be accesible on js page and you will get proper result.
Thanks
I am trying to set an arbitrary path in a JSON structure and I am having difficulty figuring out how to do a simple set value...
What I would like is some method like, SetValue(path,value) which operates like SelectToken, but creates the path if it does not exist and sets the value.
public void SetPreference(string username, string path, string value)
{
var prefs = GetPreferences(username);
var jprefs = JObject.Parse(prefs ?? #"{}");
var token = jprefs.SelectToken(path);
if (token != null)
{
// how to set the value of the path?
}
else
// how to add the path and value, example {"global.defaults.sort": { "true" }}
}
what I mean by global.defaults.sort path is actually { global: { defaults: { sort: { true } } } }
public string SetPreference(string username, string path, string value)
{
if (!value.StartsWith("[") && !value.StartsWith("{"))
value = string.Format("\"{0}\"", value);
var val = JObject.Parse(string.Format("{{\"x\":{0}}}", value)).SelectToken("x");
var prefs = GetPreferences(username);
var jprefs = JObject.Parse(prefs ?? #"{}");
var token = jprefs.SelectToken(path) as JValue;
if (token == null)
{
dynamic jpart = jprefs;
foreach (var part in path.Split('.'))
{
if (jpart[part] == null)
jpart.Add(new JProperty(part, new JObject()));
jpart = jpart[part];
}
jpart.Replace(val);
}
else
token.Replace(val);
SetPreferences(username, jprefs.ToString());
return jprefs.SelectToken(path).ToString();
}