Learning WCF (I know, late to the party)
I am working through Juval Lowy's Programming WCF book. I see that I can configure multiple endpoints (including URI's) for my service.
However, when I host these in IIS, only the location of the .svc file seems to matter. Is the multiple endpoints/addresses thing only applicable if you are self-hosting? Am I missing something about hosting services in IIS?
"only the location of the .svc ", you're heading to this because baseaddress are provided by IIS in case of web-hosting (IIS hosting) unless you're using CustomServiceHostFactory. Then whatever value you provide in address, are appended to baseaddress (.svc/..)
You needs to give several host name in IIS for the the same WCF and set several endpoints in the client section of web.config as:
<client>
<endpoint address="hostname1/myservice.svc" ... />
<endpoint address="hostname2/myservice.svc" ... />
<endpoint address="hostname3/myservice.svc" ... />
</client>
Then you can consume them as:
hostname1/myservice.svc
hostname2/myservice.svc
hostname3/myservice.svc
Related
I am consuming a web service through the debug mode in VS2013 in my project, if 14 records are there but not coming,
But when consuming via WCF Test Client, records are coming ,
please anybody can suggest me what would be the case in here ?,
configurations and service url are same,
web configuration
<endpoint address="http:/localhost:8080/SCP/Apis/Admin/Services/UserService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUserService" contract= "AdminUserService.IUserService" name="BasicHttpBinding_IUserService" />
and I call to service client like this.
var dto = new UserServiceClient().GetActiveUsers().ToList();
I'm working on a web application using mvc, we have already a service that does http binding, the client wants tcp binding for certain actions (not really sure why) but it's their requirement so i'm attempting to set up net.tcp binding, all references i am seeing to doing this involve a windows application and not a web application.
I guess my question has 2 parts, first can you run httpbinding and net.tcp binding at the same time through the same service/project.
secondly how would I consume the service through a webproject?
From "Programming WCF Services"
http://www.amazon.de/Programming-WCF-Services-Mastering-AppFabric-ebook/dp/B0043D2DUK/ref=sr_1_fkmr0_1?ie=UTF8&qid=1408811647&sr=8-1-fkmr0&keywords=programming+wcf+services+3d+edition
Every service is associated with an address that defines where the service is, a binding
that defines how to communicate with the service, and a contract that defines what the
service does. This triumvirate governing the service is easy to remember as the ABC of
the service. WCF formalizes this relationship in the form of an endpoint. The endpoint
is the fusion of the address, contract, and binding.
So, in your case you'll need to define 2 endpoints for your service.
Example from the same book:
<service name = "MyService">
<endpoint
address = "http://localhost:8000/MyService"
binding = "wsHttpBinding"
contract = "IMyContract"
/>
<endpoint
address = "net.tcp://localhost:8001/MyService"
binding = "netTcpBinding"
contract = "IMyContract"
/>
<endpoint
address = "net.tcp://localhost:8002/MyService"
binding = "netTcpBinding"
contract = "IMyOtherContract"
/>
</service>
On the client side you'll need to "Add service reference" in VS and provide an address of the desired endpoint.
http://msdn.microsoft.com/en-us/library/bb628652.aspx
1) Yes, you can set up both HTTP and a net.tcp endpoints (each of which will require it's own metadata exchange endpoints) within a service. More details here.
2) In your web application project, right click on References then click on Add Service Reference. In the dialog, copy the endpoint address of the net.tcp service. Enter the desired namespace and click ok.
I have a long-running service that gets data from one source, manipulates it, stores it in a database, etc.
I'd like to expose some methods on that service to other applications. Currently we do this via .NET Remoting but I'd like to move to WCF.
Unfortunately, I the endpoint I connect to is never the one I exposed via my long-running service. Below is a simple example:
[ServiceContract]
public interface ITestWcfService
{
[OperationContract]
CounterResult GetCurrentValue();
}
public class TestWcfService : ITestWcfService
{
private ITestWindowsService _service;
public TestWcfService() { /*NOTE: For discoverability*/ }
public TestWcfService(ITestWindowsService service)
{
_service = service;
}
public CounterResult GetCurrentValue()
{
return _service.GetCurrentValue();
}
}
public interface ITestWindowsService
{
CounterResult GetCurrentValue();
}
Then I have my actual Windows Service, which self-hosts the WCF service via the ServiceHost class.
public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
private static ServiceHost _wcfService;
public TestWindowsService()
{
InitializeComponent();
}
public void OnStart(string[] args)
{
//Create instance of WCF, passing in reference to this service instance
TestWcfService wcf = new TestWcfService(this);
_wcfService = new ServiceHost(wcf);
}
public CounterResult GetCurrentValue()
{
//Note: Some logic here
}
}
Now, this more-or-less works except that each time I make a call to the TestWcfServiceClient(), it uses the default constructor and creates a new instance of the Wcf Service and does not use the instance created by the windows service. This means that when I call GetCurrentValue() I get a null reference because the _service member hasn't been set.
I've looked around for solutions and found some citing ServiceHostFactory and ServiceHost and IInstanceProvider but each has seemed to be very, very complicated.
Any thoughts you could provide would be most appreciated.
EDIT: Here's my ServiceModel info
<system.serviceModel>
<services>
<service name="WcfService.TestWcfService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<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>
</system.serviceModel>
WCF is VERY extensible, but in order to provide such extensibility it is also very complicated. In my opinion, more than it should be so if you want to use this implementation that's the way to go. YOu have to create a behavior that changes the service factory so you can use the custom constructor instead of the empty one.
However, I think there might be another alternative. Since both the service and the WCF share the same app domain they can share values through static objects.
I would move the logic that carries the value you want to expose to un underlying assembly (if you didn't already) and both the service and WCF service would see the same instance therefore you don't need to change all the WCF plumbing.
You are trying to put a square peg in a round hole.
WCF is explicitly designed to enable calling business logic independent of how it is hosted. You are trying to maintain the old remoting design that has your business logic in the host layer (in this case a Window's service). As a result you are asking to pass information back up to the host in a way that is possible in WCF but ugly and is generally avoided for many good reasons.
If you want a clean WCF design you will need to create abstraction layers and move your business logic out of the existing TestWindowsService class. Then the windows service creates the WCF service host, the WCF host creates the WCF service, and the WCF service is not dependent on the classes that host it.
Having said all that...
To actually answer your question:
Conceptually the code that you have written should work. Passing an object instance into the ServiceHost constructor is by far the easiest way to avoid the complexity of writing a custom IInstanceProvider. A couple of things to check:
When you pass a service instance into the ServiceHost constructor it needs to be marked as a singleton.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
Make sure that initialization is really working the way you think it is:
Put a guard on your TestService(ITestWindowsService) constructor that throws if service is null.
You have a comment on the default constructor for TestWcfService() that says "for discoverability". I would remove that constructor (at least while you are troubleshooting). A piece of code might be using that constructor to host a service instance you don't want. This is likely to cause your app to start throwing exceptions or compile errors that point out your real problem.
If you are still having problems: What does the Service Model section of your app.config look like?
Is it possible to have one service with two behavior configurations? As you know it is possible to have one service and more than one endpoint where you can specify different binding configuration.
But I need to have, for the same service, different service behaviors.
If I try something like this:
<services>
<service name="Service.Service1" behaviorConfiguration="Behavior1">
<host>
<baseAddresses>
...
</baseAddresses>
</host>
<endpoint ...>
</endpoint>
</service>
<service name="Service.Service1" behaviorConfiguration="Behavior2">
<host>
<baseAddresses>
...
</baseAddresses>
</host>
<endpoint ...>
</endpoint>
</service>
</services>
... I got error "A child element named 'service' with same key already exists at the same configuration scope"
I know that I can create new class that inherits original service class but is there better solution?
Seems that you should register the same service class with another service name. Service behavior is a part of service configuration so if you want to use different behaviors you should configure different services. My question to you: if you will have one service with two behaviors, how wcf will decide to use this one or another?
Why you solution with inheritance is bad?
Quite intriguing question... I am not certain if what I am describing is possible but solution would be some thing like below:
Choose different name for service - there will be some scheme such as name="Service.Service1.Entry1"
Write custom ServiceHost (perhaps coupled with IInstanceProvider) that will ignore the last .Entry1 part and creates the service instance using Service.Service1 name.
Yet another way would be injecting dynamic type named "Service.Service1.Entry1" inherited from Service.Service1 when application is initializing. This part is very much possible - i.e. for every mentioned service, you would create n subtypes dynamically at app start-up so that you can use them as intended.
I am building an single application that uses WCF to call out to multiple external endpoints. All of the remote endpoints are identical except for the URI. I would like to treat them as a pool: add and remove endpoints through configuration and have the application understand what to do.
My original plan was to define one endoint in the app.config, then iterate over my list of endpoints and update client.Endpoint.Address on the fly to point to the right place. Unfortunately, that property is read-only, rendering that plan unworkable.
I'm a little bit stumped here. Any suggestions on how I might accomplish this?
How to: Create a Service Endpoint in Code shows you how to manage service endpoints in code rather than configuration.
Have you tried a separate name that is passed in to the client constructor?
<endpoint address="http://localhost:18000/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="BasicHttpBinding_IMyService" />
<endpoint address="http://localhost:18001/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="MyService_Secondary" />
<endpoint address="http://localhost:18002/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="MyService_Tertiary" />
Store the end point addresses in a DB table and use Jason's suggestion for creating end points in code. When a new endpoint shows up you just add another row to the table and force the service to re-query the endpoint table.
How to: Create a Service Endpoint in Code
http://msdn.microsoft.com/en-us/library/ms731080.aspx