Adding new MediaType to NewtonsoftJsonInputFormatter doesn't work - json.net

I'd like to add a new MediaType to the MvcOptions input formatter in .Net 5
When I do the following
services.AddControllers();
services.Configure<Microsoft.AspNetCore.Mvc.MvcOptions>(options =>
{
options.InputFormatters
.OfType<Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter>()
.First()
.SupportedMediaTypes
.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
});
everything works fine. But I want to use Newtonsoft.Json instead of the default Json-Serializer so I changed my code to
services.AddControllers()
.AddNewtonsoftJson();
services.Configure<Microsoft.AspNetCore.Mvc.MvcOptions>(options =>
{
options.InputFormatters
.OfType<Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter>()
.First()
.SupportedMediaTypes
.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
});
But now every time a application/csp-report is send to the controller I get a 415 Status code.

The AddNewtonsoftJson method will add two input formatters (NewtonsoftJsonInputFormatter and NewtonsoftJsonPatchInputFormatter) and when you are calling the OfType both are returning, but because you are selecting the first one, that will be always NewtonsoftJsonPatchInputFormatter that ended up being configured with your new media type not the NewtonsoftJsonInputFormatter that you expected.
So as a possible fix the code could be like:
.AddNewtonsoftJson();
services.Configure<Microsoft.AspNetCore.Mvc.MvcOptions>(options =>
{
options.InputFormatters
.OfType<Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter>()
.First(f => !(f is Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonPatchInputFormatter))
.SupportedMediaTypes
.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
});
All information here: Adding new MediaType to NewtonsoftJsonInputFormatter doesn't work

Related

CSVHelper generic ClassMap with System.Reflection

I'm trying genericly map the properties of my class to the column names of the CSV without the need to write every single line in the ClassMap like
Map(rm => rm.PUsrCrRequestedObject).Name("#P_USR_CR_RequestedObject");
because we have very much columns with mostly the same type of mapping.
So i tried the following code:
var classMap = csv.Configuration.AutoMap<RequestMonitoring>();
foreach (var property in typeof(RequestMonitoring).GetProperties())
{
var columnName = property.Name switch
{
"PNdsPn" => "$P_NDS_PN",
{ } x when x.StartsWith("PUsrCr") => property.Name.Replace("PUsrCr", "#P_USR_CR_"),
_ => property.Name
};
classMap.Map(requestMonitoring => property).Name(columnName);
}
I don't get an error but if i debug the ClassMap the code above hasn't got any effect.
So the question is how can i fix the code snippet or if it's not possible maybe how to apply the same name conversion for every property
Try this.
classMap.Map(typeof(RequestMonitoring), property).Name(columnName);

Default "Accept" header value for Asp.Net Web API

If one omits the Accept header in a request to an Asp.Net web API the server will return (415) Unsupported Media Type
I am looking for a way to force the API to assume a default return type (in my case, application/json) when the request does not contain an Accept value in its headers.
After a substantial amount of reading and searching, I'm not sure this is even possible?
You can force the framework to use XML formatter when HTTP Accept header is missing, by doing the following trick:
var jsonFormatter = config.Formatters.JsonFormatter;
config.Formatters.Remove(config.Formatters.JsonFormatter);
config.Formatters.Add(jsonFormatter);
This way the JSON formatter will be the second registered formatter in the list, and the XML will be the first one.
This is content negotiator resposibility to choose the right formatter to serialize the response object. But by default WebApi framework gets JsonFormatter if could not find appropriate formatter.
If there are still no matches, the content negotiator simply picks the first formatter that can serialize the type.
So it is strange behavior. Anyway you could set up custom content negotiator to choose explicit JsonFormatter if request does not have Accept header.
public class JsonContentNegotiator : DefaultContentNegotiator
{
protected override MediaTypeFormatterMatch MatchAcceptHeader(IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptValues, MediaTypeFormatter formatter)
{
var defaultMatch = base.MatchAcceptHeader(sortedAcceptValues, formatter);
if (defaultMatch == null)
{
//Check to find json formatter
var jsonMediaType = formatter.SupportedMediaTypes.FirstOrDefault(h => h.MediaType == "application/json");
if (jsonMediaType != null)
{
return new MediaTypeFormatterMatch(formatter, jsonMediaType, 1.0, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral);
}
}
return defaultMatch;
}
}
And replace in HttpConfiguration object
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator());

Modifying/Injecting CSS Style sheets in GeckoFX

I am trying to manipulate Style Sheets through:
GeckoFXWebBrowser.Document.StyleSheets
as mentioned here, but clearing or adding any rules as mentioned there throwing exceptions related to JSContext, also I tried to use nsIStyleSheetService similarly to what mentioned here as follows:
Dim SSS = Gecko.Xpcom.CreateInstance(Of Gecko.nsIStyleSheetService)("#mozilla.org/content/style-sheet-service;1")
Dim mUri = Gecko.IOService.CreateNsIUri("myCSSUri")
SSS.LoadAndRegisterSheet(mUri, Gecko.nsIDOMWindowUtilsConsts.USER_SHEET)
But this also throwing ambigious COM related exception.
I tried all this in DocumentCompleted event.
Any ideas what is wrong here? or how to accomplish task? (GeckoFX 29)
Since the FAQ entry was written Firefox has had some security changes which is prolly the cause of the initial exceptions.
Check out the Geckofx 29 unittests here in particular :
[Test]
public void GetCssRules_DoesNotThrowException()
{
GeckoStyleSheet styleSheet = _browser.Document.StyleSheets.First();
GeckoStyleSheet.StyleRuleCollection cssRules = null;
Assert.DoesNotThrow(() => { cssRules = styleSheet.CssRules; });
Assert.DoesNotThrow(() => { cssRules.Insert(0, "#blanc { color: white }"); });
Assert.DoesNotThrow(() => { cssRules.RemoveAt(0); });
Assert.DoesNotThrow(() => { cssRules.Clear(); });
}
As for the second method using nsIStyleSheetService:
Dim mUri = Gecko.IOService.CreateNsIUri("myCSSUri")
Is likely to work better if you specify a valid uri. (eg. http://www.google.com)

Json.Net with [WebMethod]s

I'm trying to swap out the Json formatter to Json.Net, so I can get ISO dates instead of "/Date(1379112467317)/"
I'm also letting .Net (WebForms) auto-magically handle Json serialization/deserialization through [WebMethod]s. Which don't seem to be using the Json.Net formatter.
In my global.asax, I can see the old MS Json formatter getting removed, and the new Json.net formatter added with the IsoDateTimeConverter.
But, my [Webmethod]s still come back with the old /Date()/ json strings instead of Iso dates. Do I have to do anything special in my global.asax for [Webmethod]s auto-magic to use the new formatter?
Here's the code in global:
As seen in: http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
var formatter = config.Formatters.Where(f => { return f.SupportedMediaTypes.Any(v => v.MediaType.Equals("application/json", StringComparison.CurrentCultureIgnoreCase)); }).FirstOrDefault();
if (formatter != null)
{
config.Formatters.Remove(formatter);
}
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
config.Formatters.Add(new JsonNetFormatter(serializerSettings));
I think the way that you setup the formatter looks fine for me. but how do you make sure it is being use in the webform returns, it doesn't happen automatically.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Something GetSomething()
{
}
how about you try that.

Dynamic sitemap, database driven

I've been struggling with this for a couple of days now. Can't find any good example, or an example that I understand.
Background:
I own a small blog platform for user to blog.
Each user gets their own subdomain and for now there is no sitemap available. Not good.
I want to create some kind of dynamic sitemap, where all sitemapnodes is retreived from the database. The sitemap will be used only for the search engine spiders.
System: ASP.NET, mySQL.
The sitemap is pure XML. So I need in some way to create an ASPX file that return xml-data instead of html.
And I need to somehow redirect the web.sitemap to that dynamic file.
I have never worked with XML, and I dont know how to create a file that creates XML data. So i dont even know what to search for.
I don't want any static sitemap file to be stored on the server. Everything should be created on the fly.
So. Please. If you can give me some advise about XML, any example on the internet, or just what to search for.
My main questions:
1.
How to create XML output from aspx file?
2.
How do I "inform" the system, and search engine crawlers that the file to crawl is "/sitemap.aspx"
ThankS!
I looked into MvcSiteMapProvider.MVC5 and I could not get it to work. First of all it modified my Web.config to the point that my css and js files were getting a 404 not found when running my web app.
With the time I spent getting MvcSiteMapProvider to work I could have just wrote my own.
So... here is my own dumbed down version of generating a sitemap xml.
The only thing is you have to specify your routes manually. I haven't added reflection yet to go through each controller and pull out each action.
The data-driven piece works very well though.
In your Home controller add the action Sitemap and the private helper methods.
GetRouteUrls is the manually added controller/action routes.
GetDynamicUrls builds the data-driven Urls. In my example I have a LiquidsController and a Details(string id) action.
public ActionResult Sitemap()
{
var xml = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("urlset",
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")
, GetRouteUrls()
, GetDynamicUrls()
)
);
return new XmlActionResult(xml);
}
private List<XElement> GetDynamicUrls()
{
var result = new List<XElement>();
using (var db = new ApplicationDbContext())
{
var liquids = db.Liquids.ToList();
foreach (var liquid in liquids)
{
result.Add(LocUrl("Liquids", "Details", liquid.FriendlyId));
}
}
return result;
}
private List<XElement> GetRouteUrls()
{
var result = new List<XElement>();
result.Add(LocUrl("Account", "Register"));
result.Add(LocUrl("Account", "Login"));
result.Add(LocUrl("Home", "Index"));
result.Add(LocUrl("Home", "About"));
result.Add(LocUrl("Home", "Contact"));
result.Add(LocUrl("Home", "TermsOfService"));
result.Add(LocUrl("Home", "PrivacyStatement"));
result.Add(LocUrl("Liquids", "Index"));
result.Add(LocUrl("Vendors", "Index"));
result.Add(LocUrl("Hardware", "Index"));
return result;
}
private XElement LocUrl(string controller, string action, string id = null)
{
if (!string.IsNullOrEmpty(id))
action = string.Format("{0}/{1}", action, id);
var baseUri = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
return new XElement("url",
new XElement("loc", string.Format("{0}{1}/{2}", baseUri, controller, action))
);
}
I then added a route so I could access the sitemap doing /sitemap
routes.MapRoute(name: "sitemap", url: "sitemap", defaults: new {controller = "Home", action = "Sitemap"});
The XmlActionResult return type can be found here:
Return XML from a controller's action in as an ActionResult?

Resources