I am writing a WCF client for a service (not WCF). Getting an error that Unprocessed 'mustUnderstand' header element: {http://www.w3.org/2005/08/addressing}Action, because request SOAP contains header with mustunderstand='true'. I have to either set it false or remove the whole header. can you show the way to do that?
Here is the binding code
var transportElement = new HttpsTransportBindingElement();
transportElement.AuthenticationScheme = AuthenticationSchemes.Basic;
var messegeElement = new TextMessageEncodingBindingElement();
messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11);
var binding = new CustomBinding(messegeElement, transportElement);
return binding;
I resolved this one by setting AddressingVersion to None that did not put the SOAP headers.
here is the code
MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None)
Specifying the messageVersion solved my problem.
<mtomMessageEncoding messageVersion="Soap12"/>
Related
I am trying to call a WCF service method from an .NET Core Web API using the new Visual Studio WCF Connected service.
But when I am testing this, I get the following error:-
The content type multipart/related; type="application/xop+xml"; start="http://tempuri.org/0"; boundary="uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a+id=1197"; start-info="text/xml" of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the response were: '
--uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a+id=1197
Content-ID: http://tempuri.org/0
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
The exposed WCF service uses MTOM MessageEncoding and in traditional .NET framework client application, we can set the client to use MTOM in the application's config file but in .NET core, we don't have the config file where we can set the MessageEncoding and all this configuration
is taken care of in the code present in Reference.cs(which is a generated file).
I thinking changing this generated file to set the MessageEncoding is not a good option.
Any idea on what is the best way to handle this issue?
I just came to know from WCF Core team that currently MTOM encoding is not supported in .NET Core based clients. This is a requested feature which will be available in future versions.
Here is github link which has more information: Adding MTOM support in WCF runtime
I was facing the same MTOM consumtion issue in my project, and had to find a way to be able to consume the service.
It ended up in some (ugly) code, but functional.
I just wanted to share the solution (as I wasn't able to find anything on the web) :
To start, generate the Client with Visual Studio (2017 in my case) by adding a connected service (as you would do for a regular SOAP client).
This will help you save lot a dummy code typing ;)
then, use RestSharp to call the endpoint, and serialize manually the response/request :
var client = new RestClient("http://myService/Service");
var request = new RestRequest(Method.POST);
request.AddHeader("accept", "text/plain");
request.AddHeader("content-type", "text/xml");
// create parameter
var serializer = new XmlSerializer(typeof(myParameter));
var requestParameter = new myParameter(1,2,3,4);
string requestParameterStr;
var namepsaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, NamespaceHandling = NamespaceHandling.OmitDuplicates }; // some parameters to make it clean, only OmitXmlDeclaration is mandatory
using (var stringWriter = new StringWriter())
{
using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
serializer.Serialize(xmlWriter, requestParameter, namepsaces);
requestParameterStr = stringWriter.ToString();
}
}
// patch parameter to add the namespace prefix required by consumer service
requestParameterStr = requestParameterStr.Replace("myParameter", "myNs:myParameter");
// wrap parameter in a soap envelop
requestParameterStr =
$"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:myNs=\"http://myService/Service/\"><soapenv:Header/><soapenv:Body>{requestParameterStr}</soapenv:Body></soapenv:Envelope>";
request.AddParameter(
"text/xml",
requestParameterStr,
ParameterType.RequestBody);
var response = client.Execute(request);
var mtomMsg = response.Content;
// remove MTOM elements from the received Content. here comes the ugly part ^^
var responseContentType = response.ContentType;
var contentTypeElements = responseContentType.Split(";");
var boundary = contentTypeElements.FirstOrDefault(x => x.TrimStart().StartsWith("boundary="))?.Trim().Substring("boundary=".Length);
var startElement = contentTypeElements.FirstOrDefault(x => x.TrimStart().StartsWith("start="))?.Trim().Substring("start=".Length);
boundary = boundary.Trim('"');
startElement = startElement.Trim('"');
var startIndex = mtomMsg.IndexOf(startElement) + startElement.Length;
var endIndex = mtomMsg.LastIndexOf("--" + boundary + "--", startIndex);
var cleanedMtomMsg = mtomMsg.Substring(startIndex, endIndex - startIndex);
// Get the result inside the Soap envelop
var soapDocument = XDocument.Parse(cleanedMtomMsg);
var envelopeElt = soapDocument.Root;
var bodyElt = (System.Xml.Linq.XElement)envelopeElt.FirstNode;
var responseStr = bodyElt.FirstNode.ToString();
// deserialize the result
var memstream = new MemoryStream(Encoding.UTF8.GetBytes(responseStr));
var reader = XmlDictionaryReader.CreateTextReader(memstream, XmlDictionaryReaderQuotas.Max);
var deserializer = new XmlSerializer(typeof(myResponse), "http://myService/Service/"); // don't forget the namespace
var result = deserializer.Deserialize(reader) as myResponse;
note : myParameter & myResponse are the classes generated at step 1
There could be easier ways, but at least, this works.
Hope some of you find this helpfull.
In my case, I solved this issue by using WcfCoreMtomEncoder package in my .NET Core 2.1 project. You can learn more about using it here
I fixed the problem by installing latest version of visual studio 2017. by installing latest version of visual studio it will automatically update your net core to the latest verion (1.1.2).
you can also use "binaryMessageEncodingBindingElement":
ChannelFactory<ITestService> factory = null;
ITestService serviceProxy = null;
BinaryMessageEncodingBindingElement binaryMessageEncodingBindingElement = new BinaryMessageEncodingBindingElement();
binaryMessageEncodingBindingElement.CompressionFormat = CompressionFormat.GZip;
HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
httpTransportBindingElement.MaxReceivedMessageSize = int.MaxValue;
CustomBinding customBinding = new CustomBinding(new BindingElement[] { binaryMessageEncodingBindingElement, httpTransportBindingElement });
factory = new ChannelFactory<ITestService>(customBinding, new EndpointAddress("http://localhost/test.svc/mex"));
serviceProxy = factory.CreateChannel();
var result = serviceProxy.GetResultData(50);
Is there a way to use WS2007FederationHttpBinding binding, but generate SOAP 1.1 request envelop? I need to use WS2007FederationHttpBinding to authenticate using a bearer token acquired from an STS service. Here is my bindings:
private static Binding GetWS2007FederationHttpBinding()
{
var binding = new WS2007FederationHttpBinding(
WSFederationHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.NegotiateServiceCredential = false;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
//binding.MessageVersion.Addressing = AddressingVersion.WSAddressingAugust2004;
//binding.MessageVersion.Envelope = EnvelopeVersion.Soap11;
// or
//binding.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;
return binding;
}
But I can't change binding.MessageVersion because it's a read-only property?
You would need a custom binding for that. One way would be to statically declare a custom binding equivalent to WS2007FederationHttpBinding - could take a while to fine tune it. Or you could create WS2007FederationHttpBinding in code (like you do), clone it into a custom binding:
CustomBinding outputBinding = new CustomBinding(federationBinding.CreateBindingElements());
and then find the text message encoding channel and change its soap version.
I currently have a WCF client that is able to do ad-hoc service discovery to find (unknown) services running on the local subnet. I would like to implement a way for the user to specify a service endpoint to use by entering a URI into a text box, and for the client to resolve this URI to an EndpointAddress, and in the process gather additional metadata about the service. Namely, I need to gather the EndpointIdentity and additional data exposed in the Extensions property of the EndpointDiscoveryBehavior.
I am trying to achieve this by using DiscoveryClient.Resolve(), but I am only receiving null for the ResolveResponse.EndpointDiscoveryMetadata property.
String Address = "net.tcp://machine-name:12345/MyService"
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var criteria = new ResolveCriteria()
{
Address = new EndpointAddress(Address)
};
var result = discoveryClient.Resolve(criteria);
//scv is null here.....
var svc = result.EndpointDiscoveryMetadata;
I've found a lot of information out there regarding DiscoveryClient.Find(), but not so much about DiscoveryClient.Resolve().
So my questions are:
Is this the intended use of DiscoveryClient.Resolve()?
Is MetadataResolver more appropriate here?
How does one resolve an URI to a EndpointAddress and obtain other metadata?
I think you are trying to replicate functionality of svcutil.exe. In that case you may have to resolve the mex endpoint first and query service metadata from that endpoint (IMetaDataExchange). The SPN identity should be in the metadata.
Also see reference http://msdn.microsoft.com/en-us/library/ms733130.aspx
I achieved what I wanted to do like so:
String Address = "net.tcp://machine-name:12345/MyService"
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var endpoint = new EndpointAddress(new Uri(Address));
var criteria = new ResolveCriteria()
{
Address = endpoint
};
var result = discoveryClient.Resolve(criteria);
var mexClient = new MetadataExchangeClient(MetadataExchangeBindings.CreateMexTcpBinding());
var contracts = new List<ContractDescription>() { ContractDescription.GetContract(typeof(RuntimeService.Services.IWorkflowService)) };
var metaResult = MetadataResolver.Resolve(contracts, endpoint, mexClient);
var svc = metaResult.First();
I am able to get to the extension data through result and svc provides me with the correct EndpointAddress complete with the correct identity.
Thanks to #YK1 for pushing me in the right direction.
I have a WCF service that needs to know the Principal of the calling user.
In the constructor of the service I have:
Principal = OperationContext.Current.IncomingMessageHeaders.GetHeader<MyPrincipal>("myPrincipal", "ns");
and in the calling code I have something like:
using (var factory = new ChannelFactory<IMyService>(localBinding, endpoint))
{
var proxy = factory.CreateChannel();
using (var scope = new OperationContextScope((IContextChannel)proxy))
{
var customHeader = MessageHeader.CreateHeader("myPrincipal", "ns", Thread.CurrentPrincipal);
OperationContext.Current.OutgoingMessageHeaders.Add(customHeader);
newList = proxy.CreateList();
}
}
This all works fine.
My question is, how can I avoid having to wrap all proxy method calls in the using (var scope...{ [create header and add to OperationContext]?
Could I create a custom ChannelFactory that will handle adding the myPrincipal header to the operation context? Something like that would save a whole load of copy/paste which I'd rather not do but I'm not sure how to achieve it:)
Thanks
The correct time to set a WCF principal is via IAuthorizationPolicy, by specifying a custom policy in configuration. This covered in full here. If you try setting the principal at other points (an inspector, perhaps) it can get reset by the system.
I have a Silverlight 3.0 application that is using a WCF service to communicate with the database, and when I have large amounts of data being returned from the service methods I get Service Not Found errors. I am fairly confident that the solution to it is to simply update the maxItemsInObjectGraph property, but I am creating the service client progrogrammatically and cannot find where to set this property. Here is what I am doing right now:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MaxReceivedMessageSize = int.MaxValue,
MaxBufferSize = int.MaxValue
};
MyService.MyServiceServiceClient client = new MyService.MyServiceProxyServiceClient(binding, new EndpointAddress(new Uri(Application.Current.Host.Source, "../MyService.svc")));
It's not defined in binding, but in Service Behavior.
In Silveright, maxItemsInObjectGraph defaults to int.MaxValue.
Here is an article on how to change it for .NET application, but not Silverlight: Programattically setting the MaxItemsInObjectGraph property in client
A snippet of the code:
protected ISecurityAdministrationService GetSecAdminClient()
{
ChannelFactory<ISecurityAdministrationService> factory = new ChannelFactory<ISecurityAdministrationService>(wsSecAdminBinding, SecAdminEndpointAddress);
foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior =op.Behaviors.Find<DataContractSerializerOperationBehavior>() as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = 2147483647;
}
}
ISecurityAdministrationService client = factory.CreateChannel();
return client;
}
The following is a function that I've used inside a client object that inherits from
System.ServiceModel.ClientBase(Of IServiceName)
The purpose of the method is to programatically set the MaxItemsInObjectGraph value for each operation. This allows me to have much more complex structures.
Private Sub IncreaseObjectCount()
For Each op As System.ServiceModel.Description.OperationDescription In Me.Endpoint.Contract.Operations
For Each dscob As System.ServiceModel.Description.DataContractSerializerOperationBehavior In op.Behaviors.FindAll(Of System.ServiceModel.Description.DataContractSerializerOperationBehavior)()
dcsob.MaxItemsInObjectGraph = Integer.MaxValue
Next dcsob
Next op
End Sub
I usually call it in the constructors of the object.
Change the maxItemsInObjectGraph in your WCF service for each endpoint, changing it in Silverlight means the client will be able to support the behavior, but the service must support it aswell.
After changing it in your service, regenerate the proxy/update web service, and you will get a new ServiceReference.config, that will include the new maxItemsInObjectGraph value