In the current code which is using older version of RestSharp there is option to specify the default JsonSerializer, I am not able to figure out how to do specify request.JsonSerializer in version 107
var request = new RestRequest("abc");
request.AddHeader(Constants.HttpHeaderNames.ContentType, "application/json; charset=utf-8");
request.JsonSerializer = NewtonsoftJsonSerializer.Default;
Request-specific serializers are no longer supported. The proper way of using RestSharp (similar to HttpClient) is to have one instance per API client instance. Normally, an API you talk to has the same serialization for all its endpoints.
If you must use NewtonsoftJson, use it as described in the docs.
client.UseNewtonsoftJson();
And please, don't add the content type header.
Related
We migrated from .Net Core (dotnet core) 3.1 to .Net 6. We were using the System.IdentityModel.Tokens.Jwt to create a payload and generate a security token with that payload.
Our application has yet to be migrated from Newtonsoft.Json to System.Text.Json due to a lot of nonstandard property serialization that is currently favoring the former. The custom claim value contains an object that was previously serialized properly by adhering to the camelCase contract resolver that was specified in the Startup.cs configuration with regards to JSON serialization.
We upgraded from version 5.5.0 of System.IdentityModel.Tokens.Jwt to version 6.16.0 and the serialization is behaving differently.
We are using a mixture of IdentityModel well-known claims along with a custom claim. The custom claim is the only one that is an object and also the only one behaving this way. All other claims are primitive types and are written to the token as specified and expected.
This is an example of the code that is not working:
var payload = new JwtPayload()
{
{JwtRegisteredClaimNames.Iss, issuer},
{JwtRegisteredClaimNames.Iat, now},
{JwtRegisteredClaimNames.Nbf, now},
{JwtRegisteredClaimNames.Exp, exp},
{JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")},
{"role", user.UserType},
{"customClaim", customClaimObjectInstance }
};
var jwt = new JwtSecurityToken(_jwtHeader, payload);
/* Token below contains a valid base64 encoded JWT Token with
the customClaim property containing pascal values that match
the properties of the C# Poco object and not at all following
either default convention or even any JsonProperty description
attributes such as [JsonProperty("name")] that may decorate each
property of the custom object */
var token = _jwtSecurityTokenHandler.WriteToken(jwt);
My first hunch was such that it may be related to a conflict with default library of System.Text.Json. I proceeded to troubleshoot by adding the [JsonPropertyName("name")] attribute to some of the properties but did not succeed. I expected that if System.Text.Json was being used that at least those description attributes would be respected or consulted during the serialization of the claim object.
I also tried serializing the value with Newtonsoft JsonConverter.Serialize function and use the serialized value as the value of the claim key-value-pair. However, the stringified object quotes were escaped and found plenty of escaping characters ("****") all over the value which was undesired.
After some time searching online and trying to come up with the right keywords to search google and GitHub and I finally got to what I, for now, consider a workaround and not a long-term solution.
The clue was provided by this open issue on Github. I simply, to my interpretation, forced the use of the Newtonsoft serializing and deserializing delegates by specifying the following lines before instantiation of payload variable posted in the question:
JsonExtensions.Serializer = JsonConvert.SerializeObject;
JsonExtensions.Deserializer = JsonConvert.DeserializeObject;
This was the first indication of potentially System.Text.Json being forced from deep within a library. It may also be an indication that the time has come to prioritize the migration to System.Text.Json from Newtonsoft.Json.
I hope this workaround helps somebody else get to this short-term patch, and not spend as much as I did.
If I find anymore concrete ideas or clues about this matter, I will update this answer.
The code below works
/* This was the key to achieving the prior result, however
temporary it may be. */
JsonExtensions.Serializer = JsonConvert.SerializeObject;
JsonExtensions.Deserializer = JsonConvert.DeserializeObject;
var payload = new JwtPayload()
{
{JwtRegisteredClaimNames.Iss, issuer},
{JwtRegisteredClaimNames.Iat, now},
{JwtRegisteredClaimNames.Nbf, now},
{JwtRegisteredClaimNames.Exp, exp},
{JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")},
{"role", user.UserType},
{ "customClaim", customClaimObjectInstance}
};
var jwt = new JwtSecurityToken(_jwtHeader, payload);
var token = _jwtSecurityTokenHandler.WriteToken(jwt);
I am thankful for the issue on github, but more importantly to the solution suggested here.
I am setting up a .NET core service that is reading from RabbitMQ using Rebus. It seems that the request placed in RabbitMQ needs to have the .NET object namespace information. Is there a way to work around this. For example if I had a service written in Python placing items on the queue would it be possible to read and process these requests. It seems every time I test and try to send something besides the .NET object I get an exception.
System.Collections.Generic.KeyNotFoundException: Could not find the key 'rbs2-content-type' - have the following keys only: 'rbs2-msg-id'
It depends on which serializer, you're using in the receiving end.
By default, Rebus will use its built-in JSON serializer with a fairly "helpful" setting, meaning that all .NET types names are included. This enables serialization of complex objects, including abstract/interface references, etc.
This serializer requires a few special headers to be present, though, e.g. the rbs2-content-type header, which it uses to verify that the incoming message presents itself as JSON (most likely by having application/json; charset=utf-8 as its content type).
If you want to enable deserialization of messages from other platforms, I suggest you provide the necessary headers on the messages (which – at least with Rebus' built-in serializer – also includes a .NET type name of the type to try to deserialize into).
Another option is to install a custom serializer, which is a fairly easy thing to do – you can get started by registering your serializer like this:
Configure.With(...)
.(...)
.Serialization(s => s.Register(c => new YourCrazySerializer()))
.Start();
which you then implement somewhat like this:
public class YourCrazySerializer : ISerializer
{
public async Task<TransportMessage> Serialize(Message message)
{
var headers = message.Headers.Clone();
// turn into byte[] here
//
// possibly add headers
return new TransportMessage(headers, bytes);
}
public async Task<Message> Deserialize(TransportMessage transportMessage)
{
var headers = transportMessage.Headers.Clone();
// turn into object here
//
// possibly remove headers
return new Message(headers);
}
}
As you can see, it's pretty easy to modify Rebus to accept messages from other systems.
httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.pagseguro.com.br.v3+json;charset=ISO-8859-1");
Is there any bug related to how you should add a accept header to a request?
This is a request for a specific payment gateway in Brazil (pagseguro). I've already posted in their forums but none of the members seems to be using .NET Core there yet.
Message I get: Accept header is mandatory
You should try something like:
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/vnd.pagseguro.com.br.v3+json"));
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("charset=ISO-8859-1"));
DefaultRequestHeaders.Accept is a collection of string type, where you can add your header to accept using the new instance of MediaTypeWithQualityHeaderValue.
I'm getting an intermittent exception org.apache.commons.httpclient.ProtocolException: Unbuffered entity enclosing request can not be repeated. when using Apache HTTP client library 4.x with Restlet 1.1. The request entity is of type InputRepresentation, which is associated with ByteArrayInputStream of known size, with size specified at the time of instantiation.
The exception is thrown in method writeRequestBody in class org.apache.commons.httpclient.methods.EntityEnclosingMethod
if ((this.repeatCount > 0) && !requestEntity.isRepeatable()) {
throw new ProtocolException(
"Unbuffered entity enclosing request can not be repeated.");
}
To be honest, the cause of this exception is not clear (especially due to its intermittent nature). However, some research suggests that using Apache BufferedHttpEntity to wrap the request entity should help.
Is there a way to inform Restlet to use BufferedHttpEntity when passing its request to the Apache library for handling? What could be the cause of the problem?
If the entity content stream can be reproduced (repeated), which is certainly the case with ByteArrayInputStream, there is no need for BufferedHttpEntity. One just needs to make sure that the original request entity returns a new instance of InputStream from HttpEntity#getContent() method and HttpEntity#isRepeatable() returns true.
Please note though that org.apache.commons.httpclient.ProtocolException is from an older (EOL-ed) version 3.x. Please make sure you do not have some kind of version mix-up in your application
This is a limitation of the Restlet Framework connector integrating with Apache HTTP Client.
In version 2.0 of RF, there is a new ClientResource class with "retryAttempts" and "retryDelay" property that provides the same behavior, but based on the Restlet abstractions.
I am in asp.net web api. In an API method, I am calling an external web service, that returns XML response. I don't want to deserialize it. I would rather like to send it to the client as is. Initially, I am storing the response in XDocument object but when my client specifies application/xml as accept header, I see the following exception
Type 'System.Xml.Linq.XDeclaration' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
How do I get around this problem
Great Q,i simple write your problem use in api member:
[HttpGet]
[ActionName("Books")]
public HttpResponseMessage MyBook()
{
var request = new HttpResponseMessage(HttpStatusCode.OK);
var doc = XDocument.Parse(#"<books><book><author>MS</author><name>ASP.NET</name></book></books>");
request.Content = new StringContent(doc.ToString(), Encoding.UTF8, "application/xml");
return request;
}
Try this member source.
You should be able to use some controller specific settings. See here for an example