One WCF service, multiple endpoints, different context per endpoint - c#

I'm writing a multi-tenant WCF application. I've got one "general" service class that is responsible for executing some business logic. I'd like to configure WCF with Autofac in this way that each endpoint will receive different configuration params using custom configuration section e.g.:
<system.serviceModel>
<services>
<service name="MyApiService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:80000" />
</baseAddresses>
</host>
<endpoint name="Tenant1" address="tenant1" binding="basicHttpBinding" contract="IMyApiService" />
<endpoint name="Tenant2" address="tenant2" binding="basicHttpBinding" contract="IMyApiService" />
</service>
</services>
</system.serviceModel>
<apiConfigurationSection>
<service name="Tenant1" wcfServiceName="MyApiService" param1="value1" param2="value2" />
<service name="Tenant2" wcfServiceName="MyApiService" param1="value3" param2="value4" />
</apiConfigurationSection>
I'd like parameters param1 and param to be injected as a contex when matching service (by URL) is called.
Could you suggest me any solution how to do this?

Related

How I access app settings key inside web.config

I have many services with the same main path, so I'm looking to add the main path to app settings keys and access it on baseAddress.
just as below code, what I could use instead of {baseAddress}?
<appSettings>
<add key="baseAddresses"value="https://localhost:4434/X/"/>
</appSettings>
<service name="X.Services.Proxy.MOF" behaviorConfiguration="restServiceBehave">
<host>
<baseAddresses>
<add baseAddress="{baseAddresses}/MOF.svc" />
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="rest" bindingConfiguration="NormalRequestBinding" contract="X.Services.Proxy.MOF" name="MOF" />
</service>
You can do it:
ConfigurationManager.AppSettings["{your_key}"]

Can't access WCF service after versioning service contracts

I'm having trouble figuring out an issue with a WCF service that has appeared after I have implemented a "v2" contract to it to extend functionality. Everything builds fine but when I try to access the service in the browser I just get told that it cannot connect. When I try to add it as a service reference I get a similar message regarding connection issues. However, when I remove the extended contract's endpoint from the config file, and leave the previous "v1" version intact, it works fine.
Here is the "v1" contract:
namespace Company.Services.Ticketing.Retail.Contracts
{
[ServiceContract(Name = "OutletReportingContract_v1", Namespace = "https://enterprise.company.ie/Services/Retail")]
public interface IOutletReportingContract_v1
{
/* methods */
}
}
And here is the "v2" contract:
namespace Company.Services.Ticketing.Retail.Contracts
{
[ServiceContract(Name = "OutletReportingContract_v2", Namespace = "https://enterprise.company.ie/Services/Retail")]
public interface IOutletReportingContract_v2 : IOutletReportingContract_v1
{
/* methods */
}
}
Here are the endpoints in the Web.config:
<service name="Company.Services.Ticketing.Retail.OutletService" behaviorConfiguration="Public">
<endpoint address="1" binding="wsHttpBinding" bindingConfiguration="Standard" name="OutletReportingContract_v1"
contract="Company.Services.Ticketing.Retail.Contracts.IOutletReportingContract_v1" />
<endpoint address="2" binding="wsHttpBinding" bindingConfiguration="Standard" name="OutletReportingContract_v2"
contract="Company.Services.Ticketing.Retail.Contracts.IOutletReportingContract_v2" />
<endpoint address="mex" binding="mexHttpsBinding" name="IMetadataExchange" contract="IMetadataExchange" />
</service>
And here is the error message that appears in the event viewer:
WebHost failed to process a request.
Sender Information: System.ServiceModel.Activation.HostedHttpRequestAsyncResult/28075619
Exception: System.Web.HttpException (0x80004005): There was no channel actively listening at 'https://phil-pc.company.local/Services/Retail/OutletService.svc/_vti_bin/ListData.svc/$metadata'. This is often caused by an incorrect address URI. Ensure that the address to which the message is sent matches an address on which a service is listening. ---> System.ServiceModel.EndpointNotFoundException: There was no channel actively listening at 'https://phil-pc.company.local/Services/Retail/OutletService.svc/_vti_bin/ListData.svc/$metadata'. This is often caused by an incorrect address URI. Ensure that the address to which the message is sent matches an address on which a service is listening.
at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result)
Process Name: w3wp
Process ID: 8148
A bit stumped now and would appreciate any help :)
You need to separate your services declaration in web.config.
Assuming your implementation classes are named OutletService_v1 & OutletService_v2 you should end up with something like that:
<services>
<service name="Company.Services.Ticketing.Retail.OutletService_v1" behaviorConfiguration="Public">
<endpoint binding="wsHttpBinding" bindingConfiguration="Standard" contract="Company.Services.Ticketing.Retail.Contracts.IOutletReportingContract_v1" />
<endpoint address="mex" binding="mexHttpsBinding" name="IMetadataExchange" contract="IMetadataExchange" />
</service>
<service name="Company.Services.Ticketing.Retail.OutletService_v2" behaviorConfiguration="Public">
<endpoint binding="wsHttpBinding" bindingConfiguration="Standard" contract="Company.Services.Ticketing.Retail.Contracts.IOutletReportingContract_v2" />
<endpoint address="mex" binding="mexHttpsBinding" name="IMetadataExchange" contract="IMetadataExchange" />
</service>
</services>

WCF Discovery to search server with net.tcp://0.0.0.0:8888 address

I am trying to find my servers with the help of WCF Discovery protocol.
Everything is nice when I specify explicit address for server, for example: net.tcp://192.168.36.18:8888.
But when I specify net.tcp://0.0.0.0:8888 address on the server to listen all interfaces I receive net.tcp://0.0.0.0:8888 on the client. Certainly, I can't use this address to connect to the server.
Physically responce for wcf discovery request is coming from real servers addresses: 192.168.36.100, 192.168.36.239 and 192.168.36.61. I can see it by Wireshark. But I can't get this adresses from FindResponce class.
Is there a way to get physical address if server was configured to listen all interfaces by WCF discovery?
Code on the client:
var discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var findResponce = discoveryClient.Find(new FindCriteria(typeof(IRadioService)));
discoveryClient.Close();
Code on the server:
var serviceHost = new ServiceHost(new RadioServer());
serviceHost.Open();
Config on the server:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="RadioServer">
<serviceDiscovery />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="RadioServer" name="Server.RadioServer">
<endpoint address="RS" binding="netTcpBinding" contract="Common.IRadioService" />
<endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://0.0.0.0:8888/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>

getting error message related to basicHttpBinding even though I'm using wsHttpBinding

I am trying to expose a WCF service at a wsHttpBinding endpoint and it gives me the following error message :
Contract requires Session, but Binding
'BasicHttpBinding' doesn't support it
or isn't configured properly to
support it.
Here is the interface :
[ServiceContract(Namespace="http://server.com/orderservices/",SessionMode=SessionMode.Required)]
public interface IOrderService
{
[OperationContract(IsInitiating=true,IsTerminating=false)]
string GetOrderNumber();
[OperationContract(IsInitiating = false, IsTerminating = true)]
void CreateOrder(string orderXML);
}
Here is my web.config file (the service is hosted in IIS 7 ) :
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="eMidWare.OrderService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="longTimeoutBinding"
contract="eMidWare.IPricingDataService">
</endpoint>
<endpoint
address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Hmmm.... check your service contract - it's a IOrderService
[ServiceContract(Namespace="http://server.com/orderservices/",SessionMode=SessionMode.Required)]
public interface IOrderService
{
}
but in your config, you're setting up an endpoint for eMidWare.IPricingDataService
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="longTimeoutBinding"
contract="eMidWare.IPricingDataService">
Therefore, I believe, .NET / WCF 4 will kick in a default endpoint, which is of basicHttpBinding for the http:// scheme by default....
If you had posted your service interface I could have said with certainty but I believe you have something like this on your service interface:
[ServiceContract(SessionMode = SessionMode.Required)]
This would require session and BasicHttpBinding does not support it. You need to use wsHttpBinding if you need to have sessions.

Expose webHttpBinding endpoint in a WCF service

I created a WCF service and exposed three endpoints which are basicHttpBinding, wsHttpBinding and webHttpBinding. This is a test service for my experiments with WCF. But, whenever I add service reference using the .svc file, I only get two (basic and ws) endpoints. There doesn't seem to be a third (webHttpBidning) endpoint being exposed for some reason.
To reproduce this issue, create a WCF application project, delete the Service1 service, add new item > WCF service named TestService, and change the config file to the following :
<system.serviceModel>
<services>
<service name="WcfTestService.TestService" behaviorConfiguration="TestServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost/WcfTestService/TestService.svc"/>
</baseAddresses>
</host>
<endpoint address="basic"
binding="basicHttpBinding"
contract="WcfTestService.ITestService" />
<endpoint address="ws"
binding="wsHttpBinding"
contract="WcfTestService.ITestService" />
<endpoint address="web"
binding="webHttpBinding"
contract="WcfTestService.ITestService" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
Here is the code for ITestService.cs:
[ServiceContract]
public interface ITestService
{
[OperationContract]
[WebInvoke]
Boolean ValidateUser(User user);
}
[DataContract]
public class User
{
[DataMember(Name = "Name")]
public String UserName { get; set; }
[DataMember]
public String Password { get; set; }
}
and for TestService.svc
public class TestService : ITestService
{
public bool ValidateUser(User user)
{
if (user.UserName == "User" && user.Password == "123")
{
return true;
}
return false;
}
}
I tried different combination of WebInvoke parameters and WebGet parameters, but failed.
Can anyone tell me why the third endpoint is not showing up in the WSDL file?
#decyclone: I have successfully exposed webHttpBindings without any issue. But I found some interesting thing when it get exposed and when it not!
I can see web binding getting exposed in Wcf Test Client.
Here are my configurations
<services>
<service behaviorConfiguration="TestWeb.Service2Behavior" name="TestWeb.Service2">
<endpoint address="" binding="wsHttpBinding" contract="TestWeb.Service2">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="web" binding="webHttpBinding" contract="TestWeb.Service2">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
Point to note here is, its working fine using VS2008 with Framework 3.5, VS2010 with Framework 3.5, when I use VS2010 and Framework 4.0 then I can't see WebHttpBinding getting exposed in WCF Test Client, however I can use that binidng to do http post in all cases.
I assume that in Framework 4.0 its not visible by default, even I try enable endpointDiscovery but still no luck!
I have covered this behaviour in my post
Your "web" endpoint will be exposed as a JSON endpoint. It is not compatible with WSDL.
WebHttpBinding is in System.ServiceModel.Web. If you are using vs2010, go to properties of your project, check target framework. By default it points to .Net Framework 4 Client Profile. It should point to .Net Framework 4, then you can find the System.ServiceModel.Web when you will go to Add reference
#decyclone: One way that a javascript client can learn the available methods on a webHttpBinding is to download a WCF javascript proxy with HTML script tags pointing to your endpoint followed by "/js": <script src="http://localhost/WcfTestService/TestService.svc/web/js"></script>

Categories

Resources