Programmatically adding an endpoint - wcf

I have a WCF service that I am connecting in client application. I am using following in configuration file.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyNameSpace.TestService" 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="524288" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9100/TestService" binding="basicHttpBinding"
bindingConfiguration="MyNameSpace.TestService" contract="TestService.IService" name="MyNameSpace.TestService" />
</client>
</system.serviceModel>
In the code, I am calling API on this service as follows,
TestServiceClient client = new TestServiceClient()
client.BlahBlah()
Now I want to defined endpoint porgramatically. How can that be done? I commented out section from config file as I was thinking I will have to put some code on TestServiceClient instance to add endpoint dynamically but then it throws following exception at the point where TestServiceClient is instantiated.
Could not find default endpoint element that references contract
'TestService.IService' in the ServiceModel client configuration
section. This might be because no configuration file was found for
your application, or because no endpoint element matching this
contract could be found in the client element.
How can I accomplish this? Also any point on code examples for adding endpoint programmatically will be appreciated.

To create endpoints and bindings programmatically, you could do this on the service:
ServiceHost _host = new ServiceHost(typeof(TestService), null);
var _basicHttpBinding = new System.ServiceModel.basicHttpBinding();
//Modify your bindings settings if you wish, for example timeout values
_basicHttpBinding.OpenTimeout = new TimeSpan(4, 0, 0);
_basicHttpBinding.CloseTimeout = new TimeSpan(4, 0, 0);
_host.AddServiceEndpoint(_basicHttpBinding, "http://192.168.1.51/TestService.svc");
_host.Open();
You could also define multiple endpoints in your service config, and choose which one to connect to dynamically at run time.
On the client program you would then do this:
basicHttpBinding _binding = new basicHttpBinding();
EndpointAddress _endpoint = new EndpointAddress(new Uri("http://192.168.1.51/TestService.svc"));
TestServiceClient _client = new TestServiceClient(_binding, _endpoint);
_client.BlahBlah();

Can you just use:
TestServiceClient client = new TestServiceClient();
client.Endpoint.Address = new EndPointAddress("http://someurl");
client.BlahBlah();
Note that your binding configuration will no longer apply, as you're not using that endpoint configuration in your configuration file. You'll have to override that, too.

You can try:
TestServiceClient client = new TestServiceClient("MyNameSpace.TestService")
client.BlahBlah()
if not recheck namespace in file TestService is correct?

Related

How do I consume a WS-Security service in WCF over HTTPS?

I'm trying to consume a WS-Security enabled service with WCF. Authentication works using a UsernameToken. I'm not very knowledgeable with WCF web service clients, but I think my configuration below works for regular HTTP communication. I (mostly) used this guide to configure it. The main difference is that I used the VS2010 "Add Service Reference" UI instead of a command prompt.
My problem is that I need to do this over HTTPS. When I use <security mode="Message"> in my app.config, I believe my soap envelope contains the needed WS-Security headers. I can't tell for sure because I can't get logging to work. However, I get the following error: The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via.
Below are the contents of my app.config file, as well as a sample of my client code.
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="Omitted" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Message">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" negotiateServiceCredential="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://omitted.com/service" binding="wsHttpBinding" bindingConfiguration="Omitted" contract="Omitted.Omitted" name="Omitted" />
</client>
</system.serviceModel>
var service = new OmittedClient();
service.ClientCredentials.UserName.UserName = "username";
service.ClientCredentials.UserName.Password = "password";
var response = service.DoSomething(new DoSomethingRequest());
Thanks to 500 - Internal Server error for helping me figure it out. Here are the steps I took:
Generate a proxy using Visual Studio/WCF.
Change the security mode to TransportWithmessageCredential.
Use the following code to specify a username/password.
var client = new WebServiceClient();
client.ClientCredentials.UserName.UserName = "USERNAME";
client.ClientCredentials.UserName.Password = "PASSWORD";
If you get a response back, but WCF complains when processing it, there might be a timestamp missing from the response. If that's the case, try this to fix it.
// WCF complains about a missing timestamp (http://www.west-wind.com/weblog/posts/2007/Dec/09/Tracing-WCF-Messages)
var elements = service.Endpoint.Binding.CreateBindingElements();
elements.Find().IncludeTimestamp = false;
service.Endpoint.Binding = new CustomBinding(elements);

How does WCF Client retain login session

I have a WCF client connecting to a WCF Service hosted in IIS via WsHttpBinding with Message level security and UserName client credential type.
In the client, I specify my username and password in an instance of the generated proxy class representing the service. The one proxy instance is used for all subsequent calls, and the service authenticates these credentials in the custom validator either when I explicitly call Open() or when I make my first call on the service. The validation is only made on this initial call, and not on subsequent calls. e.g.:
var client = new MyServiceClient();
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password"; client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.None;
client.GetStuff1(); // authentication is made here
client.GetStuff2(); // already authenticated, no further authentication. Why/How?
client.GetStuff3(); // already authenticated, no further authentication. Why/How?
How is this session maintained? How can I configure the server and/or client so that authentication is done on each call rather than the "session" that seems to exist? Is this not determined by the <reliableSession> which I have off?
The service class is defined with these attributes:
[ServiceBehavior(IncludeExceptionDetailInFaults = true, AutomaticSessionShutdown = false, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
The client's app.config is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingWithAuth" 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="200000000"
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="Message">
<!--
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" /> -->
<message clientCredentialType="UserName" negotiateServiceCredential="true"
algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://testmachine/MyService.svc"
binding="wsHttpBinding" bindingConfiguration="wsHttpBindingWithAuth"
contract="NewServiceIIS.IMyService" name="wsHttpBindingWithAuth">
<identity>
<certificate encodedValue="ZZZZ" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
This was the source of my frustration and now it is a bliss for you (i.e. you dont need to supply user/pass again)!
Yes, authentication is stored in the channel. Once channel opened, the ClientCredentials cannot be changed. Channel establishes a security context which is retained within the Channel. With wsHttpBinding and message security, this is username/password which is sent to the server everytime.
This is by design. The only way to re-authenticate is to close the channel/proxy and create a new proxy.
If you wonder what establishing security context is, have a look at What are the impacts of setting establishSecurityContext="False" if i use https?

LightSwitch application chokes while instantiating a WCF proxy

I'm trying to create a LightSwitch management panel for a web-based app. Thats why I was setting up a WCF RIA service to interface with the WCF service of the web app. While testing the loading of the users, I discovered that LightSwitch said that it couldn't load the resource. The Immediate Window told me that a System.InvalidOperationException had occured within System.ServiceModel.dll but VS didnt actually point me towards the loc where the error would have originated. After some line for line code execution, I discovered it choked at the instantiation of the WCF proxy.
An example of the code on the WCF RIA service Class:
Public Class RIAInterface
Inherits DomainService
Private WCFProxy As New Service.UserClient() '<-- Choke Point
Public Sub New()
WCFProxy.Open()
End Sub
<Query(IsDefault:=True)>
Public Function GetUsers() As IQueryable(Of User)
Dim TempList As New List(Of User)
For Each User As Service.User In WCFProxy.GetUsers()
TempList.Add(New User With {.ID = User.ID, .FullName = User.FullName, .EmailAddress = User.Email, .Username = User.UserName, .Class = User.Class.Name, .AccountType = User.Privilege.Name})
Next
Return TempList.AsQueryable
End Function
End Class
After some fooling arround with the RIA service and LightSwitch, something changed. I ran the app and got an actual exception.
Exception Details:
Could not find endpoint element with name 'EduNetBackEnd_IUser' and contract 'EduNet.IUser' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.
This is the the ServiceModel configuration in the App.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="EduNetBackEnd_IUser" 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:15:00"
enabled="true" />
<security mode="None">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="[Service_Address]"
binding="wsHttpBinding" bindingConfiguration="EduNetBackEnd_IUser"
contract="EduNet.IUser" name="EduNetBackEnd_IUser" />
</client>
</system.serviceModel>

The max message size quota for incoming messages (65536) ....To increase the quota, use the MaxReceivedMessageSize property

I got this crazy problem I'm trying to deal with. I know that when we're getting huge amount of data we must increase the quota on client .config file, but what am I supposed to do if my client is sending huge data "to" the WCF server?
It works perfectly normal when I'm sending small sized input parameter. Unfortunately, it breaks down when the input grows bigger.
Debugger it says:
Bad Request, 400;
on trace file it is:
The maximum message size quota for incoming messages (65536) has
been exceeded. To increase the quota, use the MaxReceivedMessageSize
property on the appropriate binding element.
Is there some way to increase this quota of incomming data on the server side? if so, how?
Here's my sample config related parts:
<bindings>
<basicHttpBinding>
<binding name="MyBasicHttpBinding"
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="64" 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>
<services>
<service name="MyWcfService">
<endpoint address="http://myservice..."
binding="basicHttpBinding" bindingConfiguration="MyBasicHttpBinding"
name="MyBasicHttpBinding" contract="IMyContract" />
</service>
</services>
and here's my client-side code (I create it dynamically):
var binding = new BasicHttpBinding();
binding.MaxBufferPoolSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxReceivedMessageSize = 2147483647;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.ReaderQuotas.MaxDepth = 2147483647;
binding.ReaderQuotas.MaxBytesPerRead = 2147483647;
var address = new EndpointAddress("http://mylocalservice..");
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>(binding, address);
foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior =
op.Behaviors.Find<DataContractSerializerOperationBehavior>()
as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = 2147483646;
}
}
public IMyContract MyClientObject = factory.CreateChannel();
You can set the MaxReceivedMessageSize property on the service via the service's config file.
Setting the client's MaxReceivedMessageSize only affects messages received by the client; it has no effect on messages received by the service. Correspondingly, to allow the service to receive large messages, you need to set the service's config file.
Sample Service Config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyBinding" maxReceivedMessageSize="2147483647" />
</wsHttpBinding>
</bindings>
<services>
<service name="MyService">
<endpoint address="http://myservice" binding="wsHttpBinding"
bindingConfiguration="MyBinding" contract="IMyServiceContract" />
</service>
</services>
</system.serviceModel>
The above is a very stripped down config file, but shows the relevant parts. The important part is that you define the binding and give it a name, and set any values explicitly that are different from the defaults, and use that name in the bindingConfiguration attribute on the endpoint element.
My problem was with the wcf test client. For some reason, it wouldn't generate a client config with the increased maxReceivedMessageSize. My fix was to right click "Config file" -> "Edit with SvcConfigEditor" -> bindings -> maxReceivedMessageSize.
This issue can be resolved by adding the below additional binding node to the binding section of config file.
<basicHttpBinding>
<binding maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>

Trying to call WCF service from inside NServiceBus Message Handler, but it hangs when creating the Service Client

Must be doing something awfully wrong here. Here is what I'm trying to do.
I have a Message handler that should get a message from the queue. Make a WCF call, do stuff and when done, send a new message out on the bus.
It is hosted in the NServiceBus.Host.Exe.
But, whenever I create the Service Client, eveything comes to a grinding halt. If I comment out the service call everything works great... Except, I need that call.
Is there a trick I must do to make WCF calls from my Message Handler when hosting it in the NServiceBus.Host.Exe? I have not made any special config in the EndPointConfig class.
public class EndpointConfig :
IConfigureThisEndpoint, AsA_Server { }
public class RequestAccountUpdateMessageHandler : IHandleMessages<RequestAccountUpdateMessage>
{
public void Handle(RequestAccountUpdateMessage message)
{
// The Line below hangs everything
AccountService.AccountServiceClient client =
new AccountService.AccountServiceClient();
resp = client.DoStuff(message.parameter);
Bus.Send<UpdateAccountMessage>(m =>
{
m.info = DoMagicStuffHere(resp);
});
}
...
}
This is what the system.serviceModel looks like in the App.Config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IAccountService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:01:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://yadayafa/accountservice.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAccountService" contract="AccountService.IAccountService" name="BasicHttpBinding_IAccountService"/>
</client>
</system.serviceModel>