Set ReaderQuotas.MaxStringContentLength, in WCF via reflection WSHttpBinding - c#

I need to consume WCF when I don't know the type of binding, it could be BasicHttpBinding or WSHttpBinding. I created a simple solution to test without reflection and it works. But when I try use it in another project via reflection, when I use WSHttpBinding, I get this exception (Spanish):
{System.Xml.XmlException: Se superó la cuota de longitud del contenido de cadena (8192) al leer los datos XML. Esta cuota se puede aumentar cambiando la propiedad MaxStringContentLength en el objeto XmlDictionaryReaderQuotas que se usa para crear el lector XML. Línea 1, posición 10572.
en System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)
en System.Xml.XmlDictionaryReader.ReadContentAsString(Int32 maxStringContentLength)
en System.Xml.XmlBaseReader.ReadContentAsString()
en System.Xml.XmlBaseReader.ReadElementContentAsString()
en System.ServiceModel.Dispatcher.PrimitiveOperationFormatter.PartInfo.ReadValue(XmlDictionaryReader reader)
en System.ServiceModel.Dispatcher.PrimitiveOperationFormatter.DeserializeParameter(XmlDictionaryReader reader, PartInfo part)
en System.ServiceModel.Dispatcher.PrimitiveOperationFormatter.DeserializeResponse(XmlDictionaryReader reader, Object[] parameters)
en System.ServiceModel.Dispatcher.PrimitiveOperationFormatter.DeserializeReply(Message message, Object[] parameters)}
in BasicHttpBinding it works ok, (when I configure WCF with this binding)
I put in the web.config this code in WsHttpBinding server
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors >
<behavior name="ServiceBehaviors" >
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
<serviceCredentials>
<serviceCertificate findValue="localhost" x509FindType="FindBySubjectName"
storeLocation="LocalMachine" storeName="My" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="TestService.CustomValidator, TestService" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Message">
<transport clientCredentialType="None" />
<message clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehaviors" name="TestService.Service1">
<endpoint binding="wsHttpBinding" contract="TestService.IService1" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
This works without reflection, to test this server I put in app.config client this simple code:
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1">
<readerQuotas maxStringContentLength="2147483647" />
<security>
<message clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
but I can't put this in my other project because the WCF could change.
I have this code in C# to configure the dynamic web service, but it doesn't work:
PropertyInfo channelFactoryProperty = proxyInstance.GetType().GetProperty("ChannelFactory");
if (channelFactoryProperty == null)
{
throw new InvalidOperationException("There is no ''ChannelFactory'' property on the DomainClient.");
}
ChannelFactory factory = (ChannelFactory)channelFactoryProperty.GetValue(proxyInstance, null);
factory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
factory.Endpoint.Binding.OpenTimeout = new TimeSpan(0, 10, 0);
factory.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
factory.Endpoint.Binding.CloseTimeout = new TimeSpan(0, 10, 0);
PropertyInfo channelFactoryPropert = proxyInstance.GetType().GetProperty("InnerChannel");
System.ServiceModel.IClientChannel factor = (System.ServiceModel.IClientChannel)channelFactoryPropert.GetValue(proxyInstance, null);
factor.OperationTimeout.Add(new TimeSpan(0, 10, 0));
factor.OperationTimeout = new TimeSpan(0, 10, 0);
switch ((factory.Endpoint.Binding).GetType().ToString())
{
case "System.ServiceModel.BasicHttpBinding":
BasicHttpBinding _basicBinding = (BasicHttpBinding)factory.Endpoint.Binding;
_basicBinding.MaxBufferPoolSize = 2147483647;
_basicBinding.MaxBufferSize = 2147483647;
_basicBinding.MaxReceivedMessageSize = 2147483647;
_basicBinding.OpenTimeout = new TimeSpan(0, 10, 0);
break;
case "System.ServiceModel.WSHttpBinding":
WSHttpBinding _wsBinding = (WSHttpBinding)factory.Endpoint.Binding;
_wsBinding.MaxBufferPoolSize = 2147483647;
_wsBinding.MaxReceivedMessageSize = 2147483647;
_wsBinding.OpenTimeout = new TimeSpan(0, 10, 0);
_wsBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
XmlDictionaryReaderQuotas _wsBindingRQ = (XmlDictionaryReaderQuotas)_wsBinding.ReaderQuotas;
_wsBindingRQ.MaxArrayLength = 2147483647;
_wsBindingRQ.MaxBytesPerRead = 2147483647;
_wsBindingRQ.MaxNameTableCharCount = 2147483647;
_wsBindingRQ.MaxStringContentLength = 2147483647;
break;
}
I don't know what code to configure in C# in the app.config in this project, it is empty.

I only needed put this code before create the instance of object. The code above (in my question) it's ok. proxyInstance = compilerResults.CompiledAssembly.CreateInstance(proxyType.Name, false, System.Reflection.BindingFlags.CreateInstance, null,
new object[] { serviceEndpoint.Binding, serviceEndpoint.Address }, System.Globalization.CultureInfo.CurrentCulture, null);

Related

Call WCF WsFederationHttpBinding service from .Net Core using STS

I have an app.config to call this service from .Net framework but now I have to do the same from core app. Here's the WCF client config:
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_certificate" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false" negotiateServiceCredential="true">
<claimTypeRequirements>
<add claimType="http://docs.oasis-open.org/wsfed/authorization/200706/claims/action" isOptional="true"/>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" isOptional="false"/>
<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"/>
</claimTypeRequirements>
<issuer address="https://some.url.com/STS/Issue.svc/trust/13/certificatemixed" binding="ws2007HttpBinding"
bindingConfiguration="certificateMixed"/>
<issuerMetadata address="https://some.url.com/STS/Issue.svc/mex"/>
<!-- THIS IS THE PROBLEM PART -->
<tokenRequestParameters>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
<Address>URN:MY.TEST.SERVICE</Address>
</EndpointReference>
</wsp:AppliesTo>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<binding name="certificateMixed">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" establishSecurityContext="false"/>
</security>
</binding>
</ws2007HttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="behaviorSECertificate">
<clientCredentials>
<clientCertificate findValue="ab cd .. b4" storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Pretty basic stuff. So now I do the same in .Net core code:
var issuerBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
issuerBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
issuerBinding.Security.Message.EstablishSecurityContext = false;
issuerBinding.Name = "certificateMixed";
var prm = new WsTrustTokenParameters
{
IssuerBinding = issuerBinding,
IssuerAddress = new EndpointAddress(_seOptions.STSEndpoint),
MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
EstablishSecurityContext = false,
};
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://docs.oasis-open.org/wsfed/authorization/200706/claims/action", IsOptional = true });
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier", IsOptional = false });
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", IsOptional = true });
var binding = new WsFederationHttpBinding(prm);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>(binding, new EndpointAddress(_seOptions.MyServiceUrl));
var cert = GetClientCertificate(); //X509Certificate2
var x = factory.Endpoint.EndpointBehaviors[typeof(ClientCredentials)];
((ClientCredentials)x).ClientCertificate.Certificate = cert;
IMyService client = factory.CreateChannel(new EndpointAddress(_seOptions.MyServiceUrl));
So the main question is- how do I add the tokenRequestParameters/AppliesTo section in code? I assume it would be something like this:
RequestSecurityToken tk = new RequestSecurityToken() { AppliesTo = new EndpointAddress("URN:MY.TEST.SERVICE") };
But I have no idea what to assign this object to.
RequestSecurityToken class is not applicable to .net core, you can see its support on this page: RequestSecurityToken Class. So you need to find a replacement for it in .net core. You can refer to Overview of porting from .NET Framework to .NET Core to consider how to migrate from .net framework to .net core. Hope my answer will help you.

Why WCF nettcpBinding is slow on local machine

I am trying to check the WCF latency on my local machine. And it takes 2-4 millisecond/request (which seems to slow). I am not sending or receiving any complex object (so no serialization/deserialization involved).
Here is the service part:
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Here is the server's config.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<bindings>
<netTcpBinding>
<binding name="defaultNetTcpBinding" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" maxBufferSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
<security mode="None"></security>
</binding>
</netTcpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<services>
<service name="WcfTestApplication.Service1">
<endpoint address="net.tcp://localhost/WcfTestApplication/Service1.svc" contract="WcfTestApplication.IService1" binding="netTcpBinding" />
<endpoint address="mex" contract="IMetadataExchange" binding="mexTcpBinding"/>
</service>
</services>
And here is the client code
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
EndpointAddress address = new EndpointAddress("net.tcp://localhost/WcfTestApplication/Service1.svc");
ChannelFactory<IService1> channelFactory = new ChannelFactory<IService1>(binding, address);
IService1 _clientProxy = channelFactory.CreateChannel();
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000; i++)
{
IService1 _clientProxy1 = channelFactory.CreateChannel();
var data = _clientProxy1.GetData(4);
((IClientChannel)_clientProxy1).Close();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds.ToString());
Console.ReadLine();
Updated:
Strange enough, there is no difference when I change binding to Named pipe. It still takes 2-4 millisecond/request.

WCF Service Throws Internal Server Error

I have pretty much reached my limits on this one. I have a WCF service that works when I run locally using Visual Studio 2013. I am calling the service from a WPF application.
I have checked other threads that seem to point to config settings and I've tried them with no luck.
Here is the code for my service.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
public class VerificationRequest
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "send", RequestFormat = WebMessageFormat.Json)]
public Stream Send(PatientVerificationRequest data)
{
try
{
using (StreamWriter sw = File.AppendText("RequestLog"))
{
sw.WriteLine("Request Received");
}
if (data == null)
{
return new MemoryStream(Encoding.UTF8.GetBytes("<html><body>Post Successful</body></html>"));
}
// Put back into json format
string json = JsonConvert.SerializeObject(data);
using (StreamWriter sw = File.AppendText("RequestLog"))
{
sw.WriteLine(json);
}
// Log the request to the database
// First, the actual json string
var jsonId = PhoenixProcedure.CreateCloudVerificationRequest(json);
var cvrId = PhoenixProcedure.CreateCloudVerificationRequest(data);
if (WebOperationContext.Current != null)
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
}
return new MemoryStream(Encoding.UTF8.GetBytes("<html><body>Post Successful</body></html>"));
}
catch (Exception ex)
{
Logger.Instance.WriteEvent(new LogEntry
{
Application = "DocumentVerification",
EntryType = LoggingEventType.Error,
Error = ex,
Message = "Error Sending Verification Request",
Source = "Send",
SystemUserId = 8
});
}
return null;
}
And here are the important settings in the web.config.
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="http" maxBufferSize="20971520" maxBufferPoolSize="20971520" maxReceivedMessageSize="20971520">
<readerQuotas maxDepth="32"
maxArrayLength="200000000"
maxStringContentLength="200000000"/>
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding name="efHttp" maxReceivedMessageSize="20000000"
maxBufferSize="20000000"
maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32"
maxArrayLength="200000000"
maxStringContentLength="200000000"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="DocVerify.VerificationRequest" behaviorConfiguration="ServiceBehavior">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="http" name="http" contract="DocVerify.VerificationRequest"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
Here is the App.config in the calling application.
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="WCFHttpBehavior">
<callbackDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="webhttp">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="WCFHttpBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxDepth="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647" />
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="WCFWebBinding" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:30:00" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
<binding name="VerificationBinding" allowCookies="true"
maxReceivedMessageSize="20000000" maxBufferSize="20000000" maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000"/>
</binding>
</webHttpBinding>
</bindings>
<client>
<endpoint address="http://PSICTSWEB01:65530/DocVerify/VerificationRequest.svc"
binding="webHttpBinding" bindingConfiguration="VerificationBinding"
contract="DocVerify.VerificationRequest"
behaviorConfiguration="webhttp"/>
</client>
And, finally, the code calling the service.
DocVerify.VerificationRequest rs = new VerificationRequestClient();
rs.Send(new PatientVerificationRequest
{
request_type = (int)PatientVerificationRequestType.Full,
patient_id = 120053,
fname = "FirstName",
lname = "LastName",
gender = "M",
dob_month = 2,
dob_day = 14,
dob_year = 1982,
address1 = "10 Main St.",
city = "Hampton",
state = "VA",
zipcode = "23669",
reported_income = 54000,
primary_insurance_name = "United Health Care",
primary_policy_number = "PN123456",
primary_group_number = "GN67890",
primary_policy_holder_fname = "FirstName",
primary_policy_holder_lname = "LastName"
});
The service immediately creates a log when called. The log file is never created, so the error is thrown before the actual call is made - but occurs during the rs.Send() method.
I've checked permissions on the server to make sure permissions are correct for creating the log file. It seems to me that the config files are ok, but something is obviously wrong. Does anyone have any ideas?
NEW INFO: I turned on WCF Tracing and am getting this error:
The message with To 'http://psictsweb01.psi.pri:65530/DocVerify/VerificationRequest.svc/Send' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.
Using this information, I have changed the web.config endpoint information to:
<binding name="VerificationBinding" allowCookies="true"
maxReceivedMessageSize="20000000" maxBufferSize="20000000" maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000"/>
</binding>
<service name="DocVerify.VerificationRequest" behaviorConfiguration="ServiceBehavior">
<endpoint address="http://PSICTSWEB01:65530/DocVerify/VerificationRequest.svc"
binding="webHttpBinding" bindingConfiguration="VerificationBinding" name="VerificationBinding" contract="DocVerify.VerificationRequest" behaviorConfiguration="webhttp"/>
</service>
In the application, the binding and endpoint are:
<binding name="VerificationBinding" allowCookies="true"
maxReceivedMessageSize="20000000" maxBufferSize="20000000" maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000"/>
</binding>
<endpoint address="http://PSICTSWEB01:65530/DocVerify/VerificationRequest.svc"
binding="webHttpBinding" bindingConfiguration="VerificationBinding"
contract="DocVerify.VerificationRequest"
behaviorConfiguration="webhttp"/>
The endpoints match. What am I doing wrong?
I don't think this really answers this question, but I did get a service to work. First, I created the service as a web site, something I don't think I should have to do. However, this removed the need for the endpoint address matching. Second, when creating a new .svc file in the project, it creates an interface class by default. Originally, I removed that class. I created a test service class and kept the interface this time and the service worked fine.
Unless someone sees what is wrong here, I may have to start from scratch next week and work slowly through the build process to see where I may have screwed the pooch.

Error while sending file to WCF: The request failed with HTTP status 400: Bad Request

I am trying to upload file using wcf service. I am getting The request failed with HTTP status 400: Bad Request at:
ds = WcfSpend.RegisterSupplier("blah", new SpendWcfRef.FileData
{
FileName = myFile.FileName.ToString(),
BufferData = file,
FilePosition = 1
});
WCF:
public DataSet RegisterSupplier(string SupplierId, FileData file)
{
DataSet ds = new DataSet();
return ds;
}
[ServiceContract]
public interface ISPEND
{
[OperationContract]
DataSet executeProcedure(string procedurename, string[] paramsName, string[] paramsValue, int num);
[OperationContract]
DataSet RegisterSupplier(string SupplierId, FileData file);
//[OperationContract]
//bool UploadFileData(FileData fileData);
}
[DataContract]
public class FileData
{
[DataMember]
public string FileName { get; set; }
[DataMember]
public byte[] BufferData { get; set; }
[DataMember]
public int FilePosition { get; set; }
}
APPLICATION:
ds = WcfSpend.RegisterSupplier("blah", new SpendWcfRef.FileData
{
FileName = myFile.FileName.ToString(),
BufferData = file, FilePosition = 1
});
Apllication config file:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ISPEND"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:01:00"
allowCookies="false"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647"
messageEncoding="Text"
textEncoding="utf-8"
transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None"
proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName"
algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client/>
</system.serviceModel>
WCF WEB CONFIG:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="myBindingForBigArrays"
openTimeout="00:10:00"
closeTimeout="00:10:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647">
<readerQuotas maxDepth="64"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="4096"
maxNameTableCharCount="16384"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
There could be a few things that are resulting in the error you are seeing. The first thing I would recommend is that you assign the binding configurations you created to an explicitly defined endpoint. Something like this:
<!-- This goes in the <system.serviceModel> section -->
<services>
<service name="MyService">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="myBindingForBigArrays"
contract="<namespace>.ISpend" />
</service>
</services>
The above is the configuration for the service. Make sure you fully qualify the contract name with the namespace, and the service name needs to be the same as the name in the markup of the .svc file.
You would do something similar for the client, except it would be the <client> tag, rather than <service>.
If you don't specify the binding configuration to use in the endpoint, then WCF will use the default (lower) values for the binding type you selected. An alternative is to make the binding configuration the default for that kind of binding, by omitting the name attribute.
If this doesn't solve the issue, you can also try adjusting the maxRequestLength value for the <httpRuntime> element in <system.web>. <system.web> is a child of <configuration>:
<system.web>
<httpRuntime maxRequestLength="2147483647" />
</system.web>

Wcf self hosted service with X.509 certificate connection error

I have a self hosted Wcf service running on Windows XP and am attempting to use Certificates for message security. This is being done via the service and client config files. Both service and client are running on the same machine and I have created certificates for both using makecert.exe. This worked fine when I had clientCredentialType="Windows" but when I modified the configuration files to use certificates it no longer works. The problem is that when I attempt to connect to the service from the client I am getting the following exception:
Exception Type: System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Message: Incoming binary negotiation has invalid ValueType http://schemas.xmlsoap.org/ws/2005/02/trust/tlsnego.
My configuration settings are:
Service config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBinding0" closeTimeout="00:10:00" sendTimeout="00:10:00">
<security>
<!-- <transport clientCredentialType="Certificate"/> -->
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CommMgr.ServiceBehavior">
<serviceMetadata httpGetEnabled="true" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<!--
<authentication certificateValidationMode="PeerTrust"/>
-->
<authentication certificateValidationMode="None"/>
</clientCertificate>
<serviceCertificate findValue="WcfServer" storeLocation="CurrentUser"
storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="CommMgr.Service" behaviorConfiguration="CommMgr.ServiceBehavior">
<endpoint address="http://localhost:8002/Service"
binding="wsHttpBinding"
name="DataService"
bindingNamespace="CommMgr"
contract="CommMgr.Service"
bindingConfiguration="wsHttpBinding0">
<!--
<identity>
<dns value="localhost"/>
</identity>
-->
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Service/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
<connectionStrings>
</configuration>
Client config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_Service" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="16384" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<!-- <transport clientCredentialType="Certificate"/> -->
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate findValue="WcfClient" storeLocation="CurrentUser"
storeName="My" x509FindType="FindBySubjectName" />
<serviceCertificate>
<!--
<authentication certificateValidationMode="PeerTrust"/>
-->
<authentication certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://localhost:8080/Service" behaviorConfiguration="ClientCertificateBehavior"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_Service"
contract="ServiceReference.Service" name="WSHttpBinding_Service">
<identity>
<!-- <dns value="WcfServer" /> -->
<certificate encodedValue="MIIBuTCCAWOgAwIBAgIQD6mW56bjgapOill7ECgRMzANBgkqhkiG9w0BAQQFADAWMRQwEgYDVQQDEwtSb290IEFnZW5jeTAeFw0xMDA3MjAxODMwMThaFw0zOTEyMzEyMzU5NTlaMBQxEjAQBgNVBAMTCVdjZkNsaWVudDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAv2p/0NDo4iZU35gN+k7nGXe0LZWdnP9i4MHYD3IsFcZGIamMyXwRT8//3jx+1fs1xEb+8+QbZuj8TXt/7aX6x2kz2O5tynuholP35iObDqOd7nYSXN+70QDrZ/uktPOkLrw/nfrA8sK0aZCZjfiINHCRt/izJIzESOGzDOh1if0CAwEAAaNLMEkwRwYDVR0BBEAwPoAQEuQJLQYdHU8AjWEh3BZkY6EYMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5ghAGN2wAqgBkihHPuNSqXDX0MA0GCSqGSIb3DQEBBAUAA0EALA+gVZDyjk4+qL7zAEV8esMX38X5QKGXHxBdd6K1+xApnSU79bRCWI9xU+HZ4rRhRJgtOdGQ1qfc9/WfvWXcYw=="/>
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
Try turning off the negotiateServiceCredential settings in your binding:
<wsHttpBinding>
<binding >
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="false" />
</security>
</binding>
</wsHttpBinding>
After one week of hard work, this works fine. o:)
Server:
using Demo.Auth;
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.Text;
namespace Demo.Services
{
public class TcpHostService
{
public const string CertificateName = "MyCertificateName";
public static ServiceHost GetServiceHost()
{
string tcpHost = GetTcpHost();
var portsharingBinding = new NetTcpBinding();
portsharingBinding.Security.Mode = SecurityMode.TransportWithMessageCredential;
portsharingBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
portsharingBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
var serviceHost = new ServiceHost(typeof(RemotingService), new Uri(tcpHost));
serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
serviceHost.AddServiceEndpoint(typeof(IRemote), portsharingBinding, tcpHost);
if (!File.Exists("Certificate.pfx"))
{
MakeCert();
}
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateName, false);
if (certificates == null || certificates.Count == 0)
{
InstallCert();
}
}
serviceHost.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.CurrentUser, StoreName.My,
X509FindType.FindBySubjectName, CertificateName);
Console.WriteLine("Server escutando " + tcpHost);
return serviceHost;
}
private static void MakeCert()
{
var rsa = RSA.Create(2048);
var req = new CertificateRequest($"cn={CertificateName},OU=UserAccounts,DC=corp,DC=contoso,DC=com",
rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddIpAddress(IPAddress.Parse("127.0.0.1"));
req.CertificateExtensions.Add(sanBuilder.Build());
var oidCollection = new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.2")
};
req.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(oidCollection, true));
req.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
req.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, false));
using (X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now.AddDays(-10), DateTimeOffset.Now.AddYears(5)))
{
cert.FriendlyName = "JJConsulting Integration Certificate";
// Create PFX (PKCS #12) with private key
File.WriteAllBytes("Certificate.pfx", cert.Export(X509ContentType.Pfx, "pwd123"));
// Create Base 64 encoded CER (public key only)
File.WriteAllText("Certificate.cer",
"-----BEGIN CERTIFICATE-----\r\n"
+ Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)
+ "\r\n-----END CERTIFICATE-----");
}
}
public static void InstallCert()
{
using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
var cert = new X509Certificate2("Certificate.pfx", "pwd123", X509KeyStorageFlags.PersistKeySet);
store.Open(OpenFlags.ReadWrite);
store.Add(cert); //where cert is an X509Certificate object
}
}
private static string GetTcpHost()
{
return "net.tcp://localhost:5050/myservice1";
}
}
}
Client:
private ChannelFactory<IRemote> GetChannelFactory()
{
var sTcp = "net.tcp://localhost:5050/myservice1"
var myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.TransportWithMessageCredential;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
var endpointIdentity = EndpointIdentity.CreateDnsIdentity("MyCertificateName");
var myEndpoint = new EndpointAddress(new Uri(sTcp), endpointIdentity);
var factory = new ChannelFactory<IRemote>(myBinding, myEndpoint);
factory.Credentials.UserName.UserName = User;
factory.Credentials.UserName.Password = Password;
factory.Credentials.ServiceCertificate.SslCertificateAuthentication =
new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck
};
return factory;
}
User Validator:
using System;
using System.IdentityModel.Selectors;
using System.ServiceModel;
namespace Demo.Auth
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
// This method validates users. It allows in two users, test1 and test2
// with passwords 1tset and 2tset respectively.
// This code is for illustration purposes only and
// must not be used in a production environment because it is not secure.
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!"user1".Equals(userName) || !"pwd".Equals(password))
{
throw new FaultException("Usuário ou senha inválido");
// When you do not want to throw an infomative fault to the client,
// throw the following exception.
// throw new SecurityTokenException("Unknown Username or Incorrect Password");
}
}
}
}

Categories

Resources