Signalr CORS issue - asp.net

On my server side I'm using web api 2 with signalr.
On my client side I'm using angularjs.
Here's the http request when I initiate the signalr connection:
> GET
> http://example.com/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%7B%22name%22%3A%22main%22%7D%5D&_=1416702959615 HTTP/1.1 Host: mysite.net Connection: keep-alive Pragma: no-cache
> Cache-Control: no-cache Accept: text/plain, */*; q=0.01 Origin:
> http://lh:51408 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64)
> AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65
> Safari/537.36 Content-Type: application/x-www-form-urlencoded;
> charset=UTF-8 Referer: http://localhost:51408/ Accept-Encoding: gzip,
> deflate, sdch Accept-Language: en-US,en;q=0.8 Cookie:
> ARRAffinity=9def17406de898acdc2839d0ec294473084bbc94a8f600c867975ede6f136080
And the response:
> HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache
> Transfer-Encoding: chunked Content-Type: application/json;
> charset=UTF-8 Expires: -1 Server: Microsoft-IIS/8.0
> X-Content-Type-Options: nosniff X-AspNet-Version: 4.0.30319
> X-Powered-By: ASP.NET Date: Sun, 23 Nov 2014 00:36:13 GMT
>
> 187
> {"Url":"/signalr","ConnectionToken":"6BKcLqjNPyOw4ptdPKg8jRi7xVlPMEgFUdzeJZso2bnXliwfY4WReQWHRpmB5YEZsbg14Au7AS5k5xS5/4qVheDxYoUkOjfFW0W8eAQsasjBaSQOifIilniU/L7XQ1+Y","ConnectionId":"f2fc7c47-c84f-49b8-a080-f91346dfbda7","KeepAliveTimeout":20.0,"DisconnectTimeout":30.0,"ConnectionTimeout":110.0,"TryWebSockets":true,"ProtocolVersion":"1.4","TransportConnectTimeout":5.0,"LongPollDelay":0.0}
> 0
However, in my javascript I'm getting the following error response when connecting:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhos:51408' is therefore not allowed access.
On my server side my startup method looks the following:
public void Configuration(IAppBuilder app)
{
System.Web.Mvc.AreaRegistration.RegisterAllAreas();
ConfigureOAuth(app);
GlobalConfiguration.Configure(WebApiConfig.Register);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}
Shouldn't this make sure that cors is used in signalr too or am I missing something?

For those who had the same issue with Angular, SignalR 2.0 and Web API 2.2,
I was able to solve this problem by adding the cors configuration in web.config and not having them in webapiconfig.cs and startup.cs
Changes Made to the web.config under <system.webServer> is as below
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>

You can look at this snippet from here https://github.com/louislewis2/AngularJSAuthentication/blob/master/AngularJSAuthentication.API/Startup.cs
and see if it helps you out.
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
app.Map("/signalr", map =>
{
// Setup the CORS middleware to run before SignalR.
// By default this will allow all origins. You can
// configure the set of origins and/or http verbs by
// providing a cors options with a different policy.
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
// You can enable JSONP by uncommenting line below.
// JSONP requests are insecure but some older browsers (and some
// versions of IE) require JSONP to work cross domain
//EnableJSONP = true
EnableDetailedErrors = true
};
// Run the SignalR pipeline. We're not using MapSignalR
// since this branch already runs under the "/signalr"
// path.
map.RunSignalR(hubConfiguration);
});
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
Database.SetInitializer(new MigrateDatabaseToLatestVersion<AuthContext, AngularJSAuthentication.API.Migrations.Configuration>());
}

I have faced the CORS issue in MVC.net
The issue is SignalR negoiate XHR request is issued with credentials = include thus request always sends user cookies
The server has to reply back with response header Access-Control-Allow-Credentials set to true
First approach and this is due the help of other people , configure it at web.config
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name= "Access-Control-Allow-Origin" value="http://yourdomain:port"/>
<add name="Access-Control-Allow-Credentials" value = "true"/>
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Second approach which I fought to make it work is via code using OWIN CORS
[assembly::OwinStartup(typeof(WebHub.HubStartup), "Configuration"]
namespace WebHub
{
public class HubStartUp
{
public void Configuration(IAppBuilder app)
{
var corsPolicy = new CorsPolicy
{
AllowAnyMethod = true,
AllowAnyHeader = true,
SupportsCredentials = true,
};
corsPolicy.Origins.Add("http://yourdomain:port");
var corsOptions = new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context =>
{
context.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
return Task.FromResult(corsPolicy);
}
}
};
app.Map("/signalR", map =>
{
map.UseCors(corsOptions);
var config = new HubConfiguration();
map.RunSignalR(config);
});
}
}}

In ConfigureServices-method:
services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials();
}));
In Configure-method:
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<General>("/hubs/general");
});

Related

Adding Connection: keep-alive header is not returned to client in ASP.net

Short Version
I'm adding the response header:
Connection: keep-alive
but it's not in the resposne.
Long Version
I am trying to add a header to an HttpResponse in ASP.net:
public void ProcessRequest(HttpContext context)
{
context.Response.CacheControl = "no-cache";
context.Response.AppendHeader("Connection", "keep-alive");
context.Response.AppendHeader("AreTheseWorking", "yes");
context.Response.Flush();
}
And when the response comes back to the client (e.g. Chrome, Edge, Internet Explorer, Postman), the Connection header is missing:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Expires: -1
Server: Microsoft-IIS/10.0
AreTheseWorking: yes
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Sat, 26 Feb 2022 16:29:17 GMT
What am I doing wrong?
Bonus Chatter
In addition to trying AppendHeader:
context.Response.AppendHeader("Connection", "keep-alive"); //preferred
I also tried AddHeader (which exists "for compatibility with earlier versions of ASP"):
context.Response.AddHeader("Connection", "keep-alive"); // legacy
I also tried Headers.Add:
context.Response.Headers.Add("Connection", "keep-alive"); //requires IIS 7 and integrated pipeline
What am i doing wrong?
Bonus: hypothetical motivation for the question
By default keep-alive is not allowed in ASP.net.
In order to allow it, you need to add an option to your web.config:
web.config:
<configuration>
<system.webServer>
<httpProtocol allowKeepAlive="true" />
</system.webServer>
</configuration>
This is especially important for Server-Send Events:
public void ProcessRequest(HttpContext context)
{
if (context.Request.AcceptTypes.Any("text/event-stream".Contains))
{
//Startup the HTTP Server Send Event - broadcasting values every 1 second.
SendSSE(context);
return;
}
}
private void SendSSE(HttpContext context)
{
//Don't worry about it.
string sessionId = context.Session.SessionID; //https://stackoverflow.com/a/1966562/12597
//Setup the response the way SSE needs to be
context.Response.ContentType = "text/event-stream";
context.Response.CacheControl = "no-cache";
context.Response.AppendHeader("Connection", "keep-alive");
context.Response.Flush();
while (context.Response.IsClientConnected)
{
System.Threading.Thread.Sleep(1000);
String data = DateTime.Now.ToString();
context.Response.Write("data: " + data + "\n\n");
context.Response.Flush();
}
}

While hitting from Postman i am able to access data without authrization but why not with angular 2 application

I am using a ASP.Net Web API. When i am selecting no authentication while creating web API project the same code works but when i use individual authentication it throws 401 error even after trying all possible tricks. Please help me to handle different authentication modes available in ASP. Net project creation. I did not find any proper document on individual authentication even on MSDN.
Also suggest me the recommended way to send token or credentials to the web API.
The below written code is of Angular 2 service. getOneItemDetailsCallClient is working but getOneItemDetailsCall throws 401
getOneItemDetailsCall():Observable<any>{
return this.http.get('http://localhost:56265/api/ProductDetail').map((response:Response)=>response.json());
}
getOneItemDetailsCallClient():Observable<any[]>{
return this.http.get('https://my-json-server.typicode.com/typicode/demo/posts').map((response:Response)=><OneItemComponent[]>response.json());
}
Error details:
Request URL: http://localhost:56265/api/ProductDetail
Request Method: GET
Status Code: 401 Unauthorized
Remote Address: [::1]:56265
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Headers: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Methods: true
Access-Control-Allow-Origin: *
Cache-Control: private
Content-Length: 6161
Content-Type: text/html; charset=utf-8
Date: Thu, 06 Sep 2018 18:04:04 GMT
Server: Microsoft-IIS/10.0
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcdmlwdWxzaW5naFxkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDE1XFByb2plY3RzXEZsaXBab25fQmFja2VuZFxGbGlwWm9uX0JhY2tlbmRcYXBpXFByb2R1Y3REZXRhaWw=?=
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:56265
Origin: http://localhost:4200
Pragma: no-cache
Referer: http://localhost:4200/OneItem
You are accessing the api from a different domain than the API is hosted so it is blocking your requests. Adding cross origin requests (CORS) should resolve your problem. Here is a link to ASP.NET Core CORS docs.
In Startup.cs You should be able to call:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
But may need to specify your Angular host app as the origin:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
// Shows UseCors with CorsPolicyBuilder.
app.UseCors(builder =>
builder.WithOrigins("http://localhost:4200"));
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}

Asp.net core doesn't respond to preflight request (OPTION) with proper headers of Access-Control-*?

I've added the following code in the file startup.cs.
In method: ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration);
var connection = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<Models.StaticDataContext>(options => options.UseSqlServer(connection));
services.AddMvc(o => {});
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddCors(o=> { o.AddPolicy("AllowSpecificOrigin", b => b.WithOrigins("*")); });
// Tried it without any parameter
// services.AddCors();
}
In method: Configure:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddNLog();
env.ConfigureNLog("nlog.config");
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader());
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
}
However it doesn't return the headers of Access-Control-*?
OPTIONS http://localhost:5001/api/Deal2 HTTP/1.1
Host: localhost:5001
Connection: keep-alive
Access-Control-Request-Method: PUT
Origin: http://localhost:8082
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://localhost:8082/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8
The raw response got from fiddler.
HTTP/1.1 204 No Content
Date: Sun, 27 Nov 2016 23:32:31 GMT
Server: Kestrel
And there should be some headers of the following?
Access-Control-Allow-Origin: YOUR_DOMAIN
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: YOUR_CUSTOM_HEADERS
Not sure if this is your problem, but it might help.
IIS needs to handle the preflight OPTION requests for ASP.NET Core. There is more information on this post.
My answer at the end and shows how to enable IIS to handle these requests.

Dreaded CORS issue with WebAPI and token

I swear this has happened so many times to me that I actually hate CORS.
I have just split my application in two so that one handles just the API side of things and the other handles the client side stuff.
I have done this before, so I knew that I needed to make sure CORS was enabled and allowed all, so I set this up in WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Enable CORS
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// Web API configuration and services
var formatters = config.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var serializerSettings = jsonFormatter.SerializerSettings;
// Remove XML formatting
formatters.Remove(config.Formatters.XmlFormatter);
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
// Configure our JSON output
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
serializerSettings.Formatting = Formatting.Indented;
serializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
serializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
// Configure the API route
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
As you can see, my first line Enables the CORS, so it should work.
If I open my client application and query the API, it does indeed work (without the EnableCors I get the expected CORS error.
The problem is my /token is still getting a CORS error. Now I am aware that /token endpoint is not part of the WebAPI, so I created my own OAuthProvider (which I must point out is being used in other places just fine) and that looks like this:
public class OAuthProvider<TUser> : OAuthAuthorizationServerProvider
where TUser : class, IUser
{
private readonly string publicClientId;
private readonly UserService<TUser> userService;
public OAuthProvider(string publicClientId, UserService<TUser> userService)
{
if (publicClientId == null)
throw new ArgumentNullException("publicClientId");
if (userService == null)
throw new ArgumentNullException("userService");
this.publicClientId = publicClientId;
this.userService = userService;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var user = await this.userService.FindByUserNameAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var oAuthIdentity = this.userService.CreateIdentity(user, context.Options.AuthenticationType);
var cookiesIdentity = this.userService.CreateIdentity(user, CookieAuthenticationDefaults.AuthenticationType);
var properties = CreateProperties(user.UserName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
context.AdditionalResponseParameters.Add(property.Key, property.Value);
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == this.publicClientId)
{
var redirectUri = new Uri(context.RedirectUri);
var expectedRootUri = new Uri(context.Request.Uri, redirectUri.PathAndQuery);
if (expectedRootUri.AbsoluteUri == redirectUri.AbsoluteUri)
context.Validated();
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
As you can see, In the GrantResourceOwnerCredentials method I enable CORS access to everything again. This should work for all requests to /token but it doesn't.
When I try to login from my client application I get a CORS error.
Chrome shows this:
XMLHttpRequest cannot load http://localhost:62605/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:50098' is therefore not allowed access. The response had HTTP status code 400.
and Firefox shows this:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:62605/token. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:62605/token. (Reason: CORS request failed).
For testing purposes, I decided to use fiddler to see if I could see anything else that might give me a clue as to what is happening. When I try to login, FIddler shows a response code as 400 and if I look at the raw response I can see the error:
{"error":"unsupported_grant_type"}
which is strange, because the data I am sending has not changed and was working fine before the split.
I decided to use the Composer on fiddler and replicated what I expect the POST request to look like.
When I Execute it, it works fine and I get a response code of 200.
Does anyone have any idea why this might be happening?
Update 1
Just for reference, the request from my client app looks like this:
OPTIONS http://localhost:62605/token HTTP/1.1
Host: localhost:62605
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:50098
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:50098/account/signin
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
from the composer, it looks like this:
POST http://localhost:62605/token HTTP/1.1
User-Agent: Fiddler
Content-Type: 'application/x-www-form-urlencoded'
Host: localhost:62605
Content-Length: 67
grant_type=password&userName=foo&password=bar
Inside of
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
Get rid of this:
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
Currently you are doing the CORS thing twice. Once with .EnableCors and also again by writing the header in your token endpoint.
For what it's worth, in my OWIN startup class I have this at the very top:
app.UseCors(CorsOptions.AllowAll);
I also do NOT have it in my WebAPI register method, as I'm letting the OWIN startup handle it.
Since OAuthAuthorizationServer runs as an Owin middleware you must use the appropriate package Microsoft.Owin.Cors to enable CORS that works with any middleware in the pipeline. Keep in mind that WebApi & Mvc are just middleware themselves in regards to the owin pipeline.
So remove config.EnableCors(new EnableCorsAttribute("*", "*", "*")); from your WebApiConfig and add the following to your startup class.
Note app.UseCors it must precede the app.UseOAuthAuthorizationServer
app.UseCors(CorsOptions.AllowAll)
#r3plica
I had this problem, and it is like Bill said.
Put the line "app.UseCors" at the very top in Configuration method()
(before ConfigureOAuth(app) is enough)
Example:
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration config = new HttpConfiguration();
ConfigureWebApi(config);
ConfigureOAuth(app);
app.UseWebApi(config);
}
We ran into a similar situation and ended up specifying some CORS data in the system.webServer node of the web.config in order to pass the preflight check. Your situation is slightly different than ours but maybe that would help you as well.
Here's what we added:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
</customHeaders>
</httpProtocol>
It turns out that there was no issue with CORS at all. I had an interceptor class that was modifying the headers incorrectly. I suggest for future reference, anyone else having these issues, if you have your CORS set up either in WebConfig.cs or your Startup class or even the web.config then you need to check that nothing is modifying your headers. If it is, disable it and test again.

Can't set ISO-8859-1 as charset of web-api response

I need to set charset ISO-8859-1 for the responses of my web api controllers, and not UTF-8.
The controller for testing returns a POCO object like this:
public class StudyCaseController : ApiController
{
...
// GET: api/StudyCase/5
public Study Get(int id)
{
...
}
}
I've tried to set <globalization requestEncoding="iso-8859-1" responseEncoding="iso-8859-1"/> in the Web.config, but testing with a fiddler request like this:
GET http://localhost:45988/api/StudyCase/1 HTTP/1.1
User-Agent: Fiddler
Host: localhost:45988
Accept: text/xml
I've got a response like this:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B? QzpcTUVESE9NRVxEZXNhcnJvbGxvQ1xQcm95ZWN0b3NcVmlld0NhcE1hblxWaWV3Q2FwTWFuXGFwaVxT dHVkeUNhc2VcMQ==?=
X-Powered-By: ASP.NET
Date: Tue, 24 Mar 2015 11:36:13 GMT
Content-Length: 1072
<?xml version="1.0"?>
... etc...
I've also tried to specify the charset at the request with Accept-Charset: iso-8859-1 but the same result.
For more info, i've tested it with IIS Express and IIS Server.
Thanks.
You can set supported encodings for formatters in HttpConfiguration class. 28591 is codepage for ISO-8859-1 (Latin 1).
config.Formatters.Add(new XmlMediaTypeFormatter());
config.Formatters[0].SupportedEncodings.Clear();
config.Formatters[0].SupportedEncodings.Add(Encoding.GetEncoding(28591));
Dealing with the problem my self, I found out that the problem was indeed the XML MediaTypeFormatter.
It does not support ISO-8859-1 and without the ability to change the server-side code I was forced to use another MediaTypeFormatter
https://www.nuget.org/packages/NetBike.Xml.Formatting/
or in nuget console
Install-Package NetBike.Xml.Formatting
This solved my problem (in a project using Web API 2).
Here is a demonstration of one way to set this using the HttpClient
private static HttpClient httpClient;
private static MediaTypeFormatter formatter;
private static List<MediaTypeFormatter> formatters;
public static void loadSettings()
{
//httpClient settings are set here
formatters = new List<MediaTypeFormatter>();
formatter = new NetBike.Xml.Formatting.NetBikeXmlMediaTypeFormatter();
formatters.Add(formatter);
}
public static async Task<HttpResponseMessage> GetContent(string requestMethod)
{
try
{
var returnValue = await httpClient.GetAsync(requestMethod);
return returnValue;
}
catch (Exception ex)
{
Debug.WriteLine("Communicator.GetXml: " + ex.Message);
}
return null;
}
public static async void testStuff()
{
var httpResponse = await GetContent("http://someDomain.com/someMethod");
MyModelObject myModel = await httpResponse.Content.ReadAsAsync<MyModelObject>(formatters);
}
What you want to do, is to set this as a default formatter for the whole project.
-EDIT-
Microsoft argues that this behavior is intended.
https://connect.microsoft.com/VisualStudio/feedback/details/958121
I have experienced issues with the NetBike Formatter, when formatting advanced XML objects, and even have a case where it writes BOM to the output.
Therefore I do not recommend it above the default MediaTypeSerializer, instead the solution falls back to the old "it depends"
That looks like this in code
List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter>();
MediaTypeFormatter badencodingFormatter = new NetBike.Xml.Formatting.NetBikeXmlMediaTypeFormatter();
badencodingFormatter.SupportedEncodings.Clear();
badencodingFormatter.SupportedEncodings.Add(Encoding.GetEncoding("ISO-8859-1"));
MediaTypeFormatter defaultFormatter = new CustomXmlMediaTypeFormatter();
formatters.Add(badencodingFormatter);
formatters.Add(defaultFormatter);
This makes sure that anoying encoding is handled by NetBike, but only in those (hopefully rare) cases

Resources