How to invoke WCF RESTful Service in Windows Service in asp.net? - c#

I have created below Operation Contract for POST Method in WCF RESTfule Service.
IService1.cs:-
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "/SaveCustomerPost",
BodyStyle = WebMessageBodyStyle.Wrapped)]
string SaveCustomerDetails(CustomerDetails objCustomerDetails);
[DataContract]
public class CustomerDetails
{
[DataMember]
public string Name { get; set; }
}
Windows Service:-
using (WebChannelFactory<ServiceReference1.IService1> cf = new WebChannelFactory<ServiceReference1.IService1>(new Uri("http://xxx/CustomerService.svc/SaveCustomerPost")))
{
var helloService = cf.CreateChannel();
ServiceReference1.CustomerDetails objCustomerDetails = new ServiceReference1.PANNoDetails();
objPANNoDetails.Name = "TestName";
string strResult = helloService.SaveCustomerDetails(objPANNoDetails);
}
Client App.config:-
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="CustBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="WebHttpBinding" sendTimeout="00:05:00" maxBufferSize="2147483647"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
transferMode="Streamed">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<client>
<endpoint address=""
binding="webHttpBinding" behaviorConfiguration="CustBehavior"
contract="ServiceReference1.ICustService" name="WebHttpBinding" />
</client>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="0"/>
</system.serviceModel>
There was no endpoint listening at "xxx.svc/SaveCustomerDetails" that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
When I invoke above mentioned method with WebInvoke method in window service I got above mentioned error. When I invoke above mentioned service without WebInvoke method, service is working fine. How to resolve above mentioned issue?

When creating the ChannelFactory, try to specify the service name only:
using (ChannelFactory<ServiceReference1.ICustService> factory = new ChannelFactory<ServiceReference1.ICustService>(
new WebHttpBinding(),
"http://xxx/CustomerService.svc"))
{
}

Related

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>

How to consume a WCF with changing endpoint or server address [duplicate]

I have my first WCF example working. I have the host on a website which have many bindings. Because of this, I have added this to my web.config.
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
This is my default binding http://id.web, which works with the following code.
EchoServiceClient client = new EchoServiceClient();
litResponse.Text = client.SendEcho("Hello World");
client.Close();
I am now trying to set the endpoint address at runtime. Even though it is the same address of the above code.
EchoServiceClient client = new EchoServiceClient();
client.Endpoint.Address = new EndpointAddress("http://id.web/Services/EchoService.svc");
litResponse.Text = client.SendEcho("Hello World");
client.Close();
The error I get is:
The request for security token could not be satisfied because authentication failed.
Please suggest how I may change the endpoint address at runtime?
Additional here is my client config, requested by Ladislav Mrnka
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEchoService" 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="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://id.web/Services/EchoService.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IEchoService" contract="IEchoService"
name="WSHttpBinding_IEchoService">
<identity>
<servicePrincipalName value="host/mikev-ws" />
</identity>
</endpoint>
</client>
</system.serviceModel>
So your endpoint address defined in your first example is incomplete. You must also define endpoint identity as shown in client configuration. In code you can try this:
EndpointIdentity spn = EndpointIdentity.CreateSpnIdentity("host/mikev-ws");
var address = new EndpointAddress("http://id.web/Services/EchoService.svc", spn);
var client = new EchoServiceClient(address);
litResponse.Text = client.SendEcho("Hello World");
client.Close();
Actual working final version by valamas
EndpointIdentity spn = EndpointIdentity.CreateSpnIdentity("host/mikev-ws");
Uri uri = new Uri("http://id.web/Services/EchoService.svc");
var address = new EndpointAddress(uri, spn);
var client = new EchoServiceClient("WSHttpBinding_IEchoService", address);
client.SendEcho("Hello World");
client.Close();
This is a simple example of what I used for a recent test.
You need to make sure that your security settings are the same on the server and client.
var myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.None;
var myEndpointAddress = new EndpointAddress("http://servername:8732/TestService/");
client = new ClientTest(myBinding, myEndpointAddress);
client.someCall();
app.config
<client>
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="LisansSoap"
contract="Lisans.LisansSoap"
name="LisansSoap" />
</client>
program
Lisans.LisansSoapClient test = new LisansSoapClient("LisansSoap",
"http://webservis.uzmanevi.com/Lisans/Lisans.asmx");
MessageBox.Show(test.LisansKontrol("","",""));
We store our URLs in a database and load them at runtime.
public class ServiceClientFactory<TChannel> : ClientBase<TChannel> where TChannel : class
{
public TChannel Create(string url)
{
this.Endpoint.Address = new EndpointAddress(new Uri(url));
return this.Channel;
}
}
Implementation
var client = new ServiceClientFactory<yourServiceChannelInterface>().Create(newUrl);

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