7

I want to use this WcfCoreMtomEncoder lib here in my .Net Core project but I'm not sure how to use it syntactically.

I have this code below but can't use MessageEncoding because I'm in a .Net Core project (no mtom support):

var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport) { // MessageEncoding = WSMessageEncoding.Mtom, not supported in .Net Core TransferMode = TransferMode.Streamed }; EndpointAddress endpoint = new EndpointAddress(url); var channelFactory = new ChannelFactory<T>(binding, endpoint); var webService = channelFactory.CreateChannel(); user.UserName = await webService.EncryptValueAsync(userName); user.Password = await webService.EncryptValueAsync(password); var documentAddResult = webService.DocumentAdd(document); channelFactory.Close(); 

From what I read I can replace it with this library code below and I see from the documentation for the encoder lib that the usage looks like this:

var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement()); var transport = new HttpTransportBindingElement(); var customBinding = new CustomBinding(encoding, transport); var client = new MtomEnabledServiceClient(customBinding); 

but I'm not sure what's what here? How would it be used to perform the document upload I'm trying to achieve? And is the library doing this or am I misunderstanding what it does?

If anyone can provide me an example of how to use this library to perform the document upload it would be appreciated.

4
  • On my side, I tried, it didn’t work, always the same error occurred. Commented Jan 7, 2020 at 9:53
  • Hi.What exactly did you try? Maybe you can show a snippet of your code and the error? Commented Jan 7, 2020 at 17:56
  • I created a WCF service with basichttpbinding using the Mtom coder. Then I call the service by configuring an custombinding using the Mtom encoder. I also tried to create a WCF service with the given binding, and consume it. Besides, Channel Factory with that binding also didn’t work. I don't know what the class library is used for. the GitHub issues also haven’t been solved yet. Commented Jan 8, 2020 at 5:32
  • (The content type multipart/related; type="application/xop+xml"; start="<tempuri.org/0>"; boundary="uuid:b84ef9c6-0def-4900-a3cb-27d13b846c62+id=5"; 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 435 bytes of the response were: Commented Jan 8, 2020 at 5:44

4 Answers 4

7

Proceed as follows:

  1. Generate the service client using WCF, this will result in a namespace and partial class, say DocumentWebServiceClient,
  2. in the same project and namespace, create a file to extend the partial class and implement the ConfigureEndpoint method which is intended for endpoint configuration tasks:
using System.Collections.Generic; using System.Linq; using System.ServiceModel.Channels; using System.ServiceModel.Description; using WcfCoreMtomEncoder; public partial class DocumentWebServiceClient // DocumentWebServiceClient is generated by the WCF { static partial void ConfigureEndpoint(ServiceEndpoint serviceEndpoint, ClientCredentials clientCredentials) { var messageEncodingBindingElementType = typeof(MessageEncodingBindingElement); var elements = serviceEndpoint.Binding.CreateBindingElements(); IEnumerable<BindingElement> elementsWithoutEncodingElement = elements.Where(item => !messageEncodingBindingElementType.IsAssignableFrom(item.GetType())); var existingEncodingElement = (MessageEncodingBindingElement)elements.Where(item => messageEncodingBindingElementType.IsAssignableFrom(item.GetType())).First(); var newEncodingElement = new MtomMessageEncoderBindingElement(existingEncodingElement); // Encoding is before transport, so we prepend the MTOM message encoding binding element // https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/custom-bindings var cb = new CustomBinding(elementsWithoutEncodingElement.Prepend(newEncodingElement)); serviceEndpoint.Binding = cb; } } 
Sign up to request clarification or add additional context in comments.

Comments

4

After some struggles, I managed to create a WCF service that could be consumed by the class library. But it only supports the Custombinding. Please refer to the below example.
Server-side (a console application based on Dotnet Framework 4.7.2)

class Program { static void Main(string[] args) { Uri uri = new Uri("http://localhost:21011"); MtomMessageEncodingBindingElement encoding = new MtomMessageEncodingBindingElement(); var transport = new HttpTransportBindingElement(); transport.TransferMode = TransferMode.Streamed; var binding = new CustomBinding(encoding, transport); using (ServiceHost sh = new ServiceHost(typeof(MyService), uri)) { sh.AddServiceEndpoint(typeof(IService), binding, ""); ServiceMetadataBehavior smb; smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (smb == null) { smb = new ServiceMetadataBehavior() { HttpGetEnabled = true }; sh.Description.Behaviors.Add(smb); } Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding(); sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex"); sh.Opened += delegate { Console.WriteLine("Service is ready"); }; sh.Closed += delegate { Console.WriteLine("Service is clsoed"); }; sh.Open(); Console.ReadLine(); //pause sh.Close(); Console.ReadLine(); } } } [ServiceContract] public interface IService { [OperationContract] string Test(); } public class MyService : IService { public string Test() { return DateTime.Now.ToLongTimeString(); } } 

Client-side (Core-based Console application with WcfCoreMtomEncoder nuget package, calling the service by using ChannelFactory).

 class Program { static void Main(string[] args) { var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement()); var transport = new HttpTransportBindingElement(); transport.TransferMode = TransferMode.Streamed; var binding = new CustomBinding(encoding, transport); EndpointAddress endpoint = new EndpointAddress("http://vabqia969vm:21011"); ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(binding, endpoint); var webService = channelFactory.CreateChannel(); Console.WriteLine(webService.Test()); } } [ServiceContract] public interface IService { [OperationContract] string Test(); } 

One more thing we pay attention to is that we should manually bind a certificate to the particular port on the server-side if the server using Transport security mode to secure the communication.

Netsh http add sslcert ipport=0.0.0.0 certhash=0102030405060708090A0B0C0D0E0F1011121314 appid={00112233-4455-6677-8899-AABBCCDDEEFF}

In the above example, I bind a certificate that has a named vabqia969vm subject(DNS) to the machine(hostname is vabqia969vm). Here are some official links.
https://learn.microsoft.com/en-us/windows/win32/http/add-sslcert
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
On the client-side, before making a call to the service, we should establish a trust relationship so that communication is available between the client-side and the server-side. Therefore, I install the server certificate on the client-side LocalCA(Trusted Root Certification Authorities in the certification store). Alternatively, we could manually add a certificate validation process.

ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(binding, endpoint); channelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new System.ServiceModel.Security.X509ServiceCertificateAuthentication() { CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None, RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck }; 

Feel free to let me know if there is anything I can help with.
Updated.
I have updated the above example which works properly over HTTP protocol.

3 Comments

Your code uses .Net Framework 4.7.2? My post was specifically related to .Net Core
Server-side uses .Net Framework 4.7.2, the client-side uses .Net core Sdk. That’s where the library apply in, enabling the core-based application can use Mtom encoder. Server-side based on .Net Core cannot create Wcf service applications,because it is a distributed framework based on .Net framework, has not been implemented yet in Core. gRPC is the best approach for building distributed applications in Core
@user1186050 , In the above code snippets, we can also create a service without transport layer security mode. and it can be called properly in the Dotnet Core application as well. If we do in this way, we needn't specify `https' base address, there is no need to bind a certificate, It will be easily finished. I have updated the reply, please check.
0

your .net core client code should be something like this

var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement()); var transport = new HttpTransportBindingElement(); var customBinding = new CustomBinding(encoding, transport); EndpointAddress endpoint = new EndpointAddress(url); var channelFactory = new ChannelFactory<T>(customBinding, endpoint); var webService = channelFactory.CreateChannel(); user.UserName = await webService.EncryptValueAsync(userName); user.Password = await webService.EncryptValueAsync(password); var documentAddResult = webService.DocumentAdd(document); channelFactory.Close(); 

4 Comments

Do you know if this supports https? Using it I'm getting an exception that says: "The provided URI scheme 'https' is invalid; expected 'http'"
in that case use HttpsTransportBindingElement instead of HttpTransportBindingElement
but it expects http, not https according to the message. Aren't you suggesting I do the opposite?
If your server url is http then go with httptransportbinding
0

Expanding on @divyang4481's answer. For those still struggling with this, depending on the service you are interacting with, you may have to change your encoding to something like the following:

 var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None) }); var transport = new HttpsTransportBindingElement(); var customBinding = new CustomBinding(encoding, transport); 

The web service I was calling threw an error, i.e. mustUnderstand headers with default TextMessageEncodingBindingElement, so, I had to set the AddressVersion to none to solve the issue.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.