Can I add and read a custom header in the Envelope/Header/Security element? I tried using the MessageHeader attribute, but that does not allow me to put the header in the Security element.
I created a class that implements IClientMessageInspector thinking that I could access the Security header like so:
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
Message originalMessage = buffer.CreateMessage();
foreach (MessageHeader h in originalMessage.Headers)
{
Console.WriteLine("\n{0}\n", h);
}
return null;
}
But the Security header is not present in the originalMessage.Headers object.
Create a custom message encoder: http://msdn.microsoft.com/en-us/library/ms751486.aspx.
You can access the message headers in your encoder's WriteMessage override. Note that the Message's Headers property will not contain the Security header (though this may depend on the type of security you're using). Write out the message to a stream or file using, say, Message.WriteMessage(XmlWriter). The stream/file will contain the contents of the message just before being sent over the wire, including the Security element. From there, you can modify your message as necessary and return an ArraySegment including your changes.
Related
I need access to RequestBody inside OnActionExecuting or OnActionExecuted filter, but I can not found concrete example how to use PipeReader to read full request body stream and return stream position to zero (in order to read request parameters by ControllerBase - if I read body OnActionExecuting or firstly return position to zero if I read in OnActionExecuting).
In my attribute Body always empty.
However, API parameters is present.
Or maybe there is another way to receive Request Body in Action Filter for ControllerBase?
From your description, I think you wanna get request body in multiple times in asp.net core. But in asp.net core, the request can not be read once it is consumed. If you want to read the request body multiple times, you need to set:
context.Request.EnableBuffering()
Then to read the body stream you could for example do this:
string bodyContent = new StreamReader(Request.Body).ReadToEnd();
On the safer side, set the Request.Body.Position reset to 0. That way any code later in the request lifecycle will find the request body in the state just like it hasn’t been read yet.
Request.Body.Position = 0;
So you can set this code in either OnActionExecuting or OnActionExecuted method.
public void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Request.EnableBuffering();
string bodyContent = new StreamReader(context.HttpContext.Request.Body).ReadToEnd();
context.HttpContext.Request.Body.Position = 0;
}
But please note that, Model binding happens before action filter, So Model binding will consume request body first and you can not read it in your action filter, You need to custom model binding and Apply the above configuration to it.
I have a JAX-RS #POST endpoint whose input data has to be #Valid:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response myEndpoint(#javax.validation.Valid MyInputData input) { /*...*/ }
With MyInputData class annotated with many constraints:
#lombok.Data
public class InputData {
#Size(min = 1, max = 3)
private String someString;
/* ... */
}
Beyond that I have an ExceptionMapper<ConstraintViolationException> that transform the Exception into a Collection<String> (basically every single ConstraintViolation transformed to String using its getMesssage() method), then returns a Response.status(Status.BAD_REQUEST).entity(list).build().
Everything is working nicely. Fed an invalid input and I get back a HTTP 400 with a nice array of constraint violations in json format.
So far, so good...
BUT... the messages are in server's locale. Even if HTTP post sends a Accept-language header (and it is correctly detected when getting HttpServletRequest::getLocale).
By the time the ExceptionMapper gets hold of ConstraintViolation every message has already been interpolated, so no chance set the client locale.
Since the validation runs even before the JAX-RS resource (indeed, the JAX-RS resource isn't even called in case of invalid input), this locale aware message interpolator must be configured somewhere else.
Where? Is there already a MessageInterpolator implementation whose operation takes the HttpServletRequest locale into account?
I have a WCF connected service in a .net core application. I'm using the code that is autogenerated taken the wsdl definition.
Currently at the top of the request xml is including this line:
<?xml version="1.0" encoding="utf-16"?>
I can't find a simple way to change this encoding to UTF-8 when sending the request.
Since I could find a configuration option a the request/client objects, I've tried to change the message with following code at IClientMessageInspector.BeforeSendRequest
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// Load a new xml document from current request
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(request.ToString());
((XmlDeclaration)xmlDocument.FirstChild).Encoding = Encoding.UTF8.HeaderName;
// Create streams to copy
var memoryStream = new MemoryStream();
var xmlWriter = XmlWriter.Create(memoryStream);
xmlDocument.Save(xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();
memoryStream.Position = 0;
var xmlReader = XmlReader.Create(memoryStream);
// Create a new message
var newMessage = Message.CreateMessage(request.Version, null, xmlReader);
newMessage.Headers.CopyHeadersFrom(request);
newMessage.Properties.CopyProperties(request.Properties);
return null;
}
But the newMessage object still writes the xml declaration using utf-16. I can see it while debugging at the watch window since.
Any idea on how to accomplish this (should be) simple change will be very apreciated.
Which binding do you use to create the communication channel? The textmessageencoding element which has been contained in the CustomBinding generally contains TextEncoding property.
https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/textmessageencoding
WriteEncoding property specifies the character set encoding to be used for emitting messages on the binding. Valid values are
UnicodeFffeTextEncoding: Unicode BigEndian encoding
Utf16TextEncoding: Unicode encoding
Utf8TextEncoding: 8-bit encoding
The default is Utf8TextEncoding. This attribute is of type Encoding.
As for the specific binding, it contains the textEncoding property too.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.basichttpbinding.textencoding?view=netframework-4.0
Feel free to let me know if there is anything I can help with.
This is part of a JAX-RS server which receives a response from another server and sends the same response back to its client.
This copies the entity from anotherResponse to responseForClient:
Response responseForClient = Response.fromResponse(anotherResponse).entity(anotherResponse.readEntity(InputStream.class)).build();
This doesn't copy the entity:
Response responseForClient = Response.fromResponse(anotherResponse).build();
The second one should also work as JAX-RS Response.fromResponse() should copy the entity also.
Why setting the entity is required?
I am using RestEasy-3.0.
You have to consume the InputStream before calling fromResponse because it only will copy the response. The JAX-RS won't do it automatically, and if you provide the new instance to the client then the entity will not be consumed
See the documentation of fromResponse
public static Response.ResponseBuilder fromResponse(Response response)
Create a new ResponseBuilder by performing a shallow copy of an existing Response.
The returned builder has its own response headers but the header values are shared with the original Response instance. The original response entity instance reference is set in the new response builder.
Note that if the entity is backed by an un-consumed input stream, the reference to the stream is copied. In such case make sure to buffer the entity stream of the original response instance before passing it to this method.
Buffer the response reading the InputStream to a byte array
InputStream is = anotherResponse.readEntity(InputStream.class);
byte[] bytes = IOUtils.toByteArray(is);
ByteArrayInputStream in= new ByteArrayInputStream (bytes);
This code is equivalent to yours
Response responseForClient =
Response.fromResponse(anotherResponse).entity(in).build()
I have an ASP application which is client of WCF SERVICE1 , which is client of WCF SERVICE2.
I have added IDispatchMessageInspector and IClientMessageInspector to WCF SERVICE1.
Now I need to pass a custom value from ASP to WCF1 , then to WCF2.
from ASP to WCF1 it is trivial , via Message Headers.
The question is , how to pass a custom value from IDispatchMessageInspector.AfterReceiveRequest(request from ASP received by WCF1) to IClientMessageInspector.BeforeSendRequest(prepare to send request to WCF2) operation of WCF SERVICE 1 ?
Is there is some context which could be used ?
What does your code look like? Assuming that first Dispatch Message Inspector is the one making the request to WCF2, then simply using message properties would suffice.
However, if your dispatch message inspector does something; then the request continues processing and it is the service implementation that actually calls WCF2, then you'll need to jump through a few more hoops. In general, I'd say you'd need the inspector to put some data in the service request message properties that the service implementation would need to pick up and copy to the message to send to WCF2 so that the client inspector can pick them up.
That's ugly, and would kinda make the whole process more brittle.
Can you elaborate a bit more what you're trying to do? What kind of data are you hoping to pass around this way?
In my case, I had to identify and log nested service calls requested by client.
To do that, I stamp each service call by ThreadStatic property and add this property to the header of client call(service1 count as client for service2) than in AfterReceiveRequest method I have checked its existance. If exists,current method was requested by parent service.
public class GenericMessageInspector : IDispatchMessageInspector, IClientMessageInspector
{
[ThreadStatic]
private static string _masterServiceGUID;
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
if (request.Headers.Action == null)
return null;
//Control request header for nested call
string masterRequestId = string.Empty;
var IsMasterExist = request.Headers.FindHeader("MasterServiceGUID", "namespace");
if (IsMasterExist > -1)
{
//requested by internal service
masterRequestId = request.Headers.GetReaderAtHeader(IsMasterExist).ReadInnerXml();
}
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (!String.IsNullOrEmpty(_masterServiceGUID))
{
request.Headers.Add(MessageHeader.CreateHeader("MasterServiceGUID", "namespace", _masterServiceGUID));
}
return null;
}
}
}