How to debug CustomServiceHostFactory in WCF? - wcf

I've recently implemented a CustomServiceHostFactory and am wondering how to debug it by hitting breakpoints in code. Here is the factory:
public class CustomHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ServiceHost host = new ServiceHost(serviceType, baseAddresses);
//configure WsHttpBinding
ConfigureServiceThrottling(host);
return host;
}
private void ConfigureWshttpBinding(ServiceHost host)
{
//Do something here....
}
private void ConfigureServiceThrottling(ServiceHost host)
{
ServiceThrottlingBehavior throttle = host.Description.Behaviors.Find<ServiceThrottlingBehavior>();
if (throttle == null)
{
throttle = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 100,
MaxConcurrentSessions = 100,
MaxConcurrentInstances = 100
};
host.Description.Behaviors.Add(throttle);
}
}
}
I create this in an empty web project and here are the pertinent Web.config contents.
<service name="Company.Project.Business.Services.AccountService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address=""
binding="basicHttpBinding"
contract="Company.Project.Business.Contracts.Service.IAccountService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
<service name="Company.Project.Business.Services.AccountClassService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address=""
binding="basicHttpBinding"
contract="Company.Project.Business.Contracts.Service.IAccountClassService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<serviceHostingEnvironment>
<!-- where virtual .svc files are defined -->
<serviceActivations>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="AccountService.svc"
factory="Company.Project.WebHost.CustomHostFactory"/>
<add service="Company.Project.Business.Services.AccountClassService"
relativeAddress="AccountClassService.svc"
factory="Company.Project.WebHost.CustomHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
I publish this to IIS and can successfully browse to and consume the services. Here is a path to one for example.
http://company.server.local/Project/Account/AccountService.svc
I am now trying to programmatically apply WsHttpBinding with open/close/send timeouts, readerQuotas, etc. I am trying to do this all in code and it would be helpful if I could step into the CustomeHostFactory to debug but have no idea how to do that. Any help is much appreciated. Thanks.

Ok, I was totally confused here. Instead of trying to attach to the w3wp process, I just set the project with the CustomHostFactory as the startup project in Visual Studio. I put a breakpoint in the protected override ServiceHost CreateServiceHost method.
Then, when I run the project http://localhost:58326/ comes up in a browser. I then had to actually browse to an endpoint like so: http://localhost:58326/Account/AccountService.svc in order to hit the breakpoint.
Now I can debug my programmatic configuration of the service. Hopefully this helps someone else.

Related

WCF hosted in Windows service via TCP - can't consume

I just spend 4 hours googling around trying to find why i cant consume (add service reference) WCF hosted in Windows service. Error i am getting is this
The URI prefix is not recognized.
Metadata contains a reference that cannot be resolved: 'net.tcp://localhost:8523/Service1'.
Could not connect to net.tcp://localhost:8523/Service1. The connection attempt lasted for a time span of 00:00:02.0158574. TCP error code 10061: No connection could be made because the target machine actively refused it 127.0.0.1:8523.
No connection could be made because the target machine actively refused it 127.0.0.1:8523
If the service is defined in the current solution, try building the solution and adding the service reference again.
I created a small service following this tutorial https://msdn.microsoft.com/en-us/library/ff649818.aspx to the letter. I'm stuck on step 8 where i get error i posted above.
My App.config (WCF configuration)
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<bindings />
<services>
<service name="WcfServiceLibrary1.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
name="netTcpEndpoint" contract="WcfServiceLibrary1.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="" binding="mexTcpBinding" bindingConfiguration=""
name="mexTCPendpoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8523/Service1" />
</baseAddresses>
<timeouts closeTimeout="00:01:00" openTimeout="00:02:00" />
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug httpHelpPageEnabled="false" httpsHelpPageEnabled="false"
includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Service.1.cs
public partial class Service1 : ServiceBase
{
internal static ServiceHost MyServiceHost = null;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
}
MyServiceHost = new ServiceHost(typeof(Service1));
MyServiceHost.Open();
}
protected override void OnStop()
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
MyServiceHost = null;
}
}
}
Things I've tried so far:
Turning off windows firewall
Opening port TCP 8523 (in and outbound rules)
Changing port numbers
Checking netstat -atn (TCP port 8523 is not listnening)
Double checking that serviceProcessInstaller1 has account option set to Network service
Double checking that serviceInstaller1 has StartType option set to Automatic
Double checking that Service1 is Started in services.msc
Enabled all Net.XXX Services in services.msc
Remove then Added TCP Activation and TCP Port Sharing in "Turn windows features on or off"
Ran out of ideas
Any help as to why i can't consume WCF is highly appreciated.

wcf service hosted under IIS address

I have a WCF service hosted under IIS.
I have the following configuration:
<services>
<service name="BillboardServices.LoginService" behaviorConfiguration="LoginServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://myip/LoginService/" />
</baseAddresses>
</host>
<endpoint address="" name="LoginService" binding="basicHttpBinding" contract="BillboardServices.ILoginService" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
If I enter http://myip/LoginService/, I get a 404.
If I enter http://myip/Service1.svc, I get the service metadata.
What changes to the configuration do I need in order for the service to be accessible through the nice url?
Thank you.
In order to have and extensionless service, you need to use WCF 4 and init the routing engine in the global.asax file like so:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
// Edit the base address of Service1 by replacing the "Service1" string below
RouteTable.Routes.Add(new ServiceRoute("Service1", new WebServiceHostFactory(), typeof(Service1)));
}

Edit System.Servicemodel values programmatically?

When using WCF, there is a section in the web.config as below.
<system.serviceModel>
<services>
<service name="abc">
<endpoint /> <---this
</service>
</services>
</system.serviceModel>
Is it possible to edit the area I've marked programmatically?
I can see there is a sytem.serviceModel namespace, but other than that I'm a bit lost.
If you want to change these parameters at runtime you can override ServiceHost.OnOpening()
E.g. to change port:
protected override void OnOpening()
{
foreach (ServiceEndpoint endpoint in Description.Endpoints)
{
string uriString = string.Format("{0}://{1}:{2}{3}",
endpoint.Address.Uri.Scheme,
endpoint.Address.Uri.Host,
endpoint.Address.Uri.Port + _basePort,
endpoint.Address.Uri.LocalPath);
endpoint.Address = new EndpointAddress(uriString);
}
base.OnOpening();
}
To complement Mike Mozhaev's answer, since your service is hosted in IIS you'll need a ServiceHostFactory to get a reference to the service host (or to use your own host). There's some information about it at http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/14/wcf-extensibility-servicehostfactory.aspx.

Windows service hosting a WCF service closing immediately

I tried hosting a WCF Library service with windows service project, I installed the service, however, when i start the service in services.msc, the service start and closses immediatly. Following the message that gets displayed:
The Servicel service on Local
Computer started and then stopped.
Some services stop automatically if
they are not in use by other services
or programs.
The App.config file for wcf and the windows service project is same and it is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="WorkMateWCF.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
contract="WorkMateWCF.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8523/WorkMate1" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The entire project/solution is downloadable here: https://skydrive.live.com/?cid=d358d316fa2c3a37&sc=documents&uc=1&id=D358D316FA2C3A37%21135#
Could you please guide me on how to proceed further. Thank you.
Additional information:
Following is the code from the service1.cs file in windows service project.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.ServiceModel;
using WorkMateWCF;
namespace WorkMateWinService
{
public partial class Service1 : ServiceBase
{
internal static ServiceHost MyServiceHost = null;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
}
MyServiceHost=new ServiceHost(typeof( Service1));
MyServiceHost.Open();
}
protected override void OnStop()
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
MyServiceHost = null;
}
}
}
}
What I find very confusing (and probably the .NET runtime, too) is the fact that your Windows Service is called Service1, while your WCF Service also is called Service1 (without a namespace or anything).
So which of the two Service1 class types will be used here???
MyServiceHost = new ServiceHost(typeof(Service1));
I'm not sure - and I'm afraid it will be the wrong class (the Windows NT Service class).
You should give your stuff more meaningful names and keep those things apart (by name, too) !
Got the issue, when I reviewed my event logs I found this:
"Service cannot be started. System.InvalidOperationException: The HttpGetEnabled property of ServiceMetadataBehavior is set to true and the HttpGetUrl property is a relative address, but there is no http base address. Either supply an http base address or set HttpGetUrl to an absolute address.
at System.ServiceModel.Description.ServiceMetadataBehavior.EnsureGetDispatcher(ServiceHostBase host, ServiceMetadataExtension mex, Uri url, String scheme)
at System.ServiceModel.Description.ServiceMetadataBehavior.CreateHttpGetEndpoints(ServiceDescription description, ServiceHostBase host, ServiceMetadataExtension mex)
at System.ServiceModel.Description.ServiceMetadataBehavior.ApplyBehavior(ServiceDescription description, ServiceHostBase host)
at System.ServiceModel.Description.ServiceMetadataBehavior.System.ServiceModel.Description.IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescript..."
Then after thorough reviewing, the issues is that I did HTTPSGETENABLED to false only for one, infact there are two, after making the change for the other one, the app started to work like charm.
I special

How use injection in wcf

I have two classes implementing a contract at a service which are consumed from a factory on the client like shown below.
[ServiceContract]
public interface MyInterface {
void DoSomething()
}
public class A : MyInterface {
public void DoSomething(){
"Hi I'm A"
}
}
public class B : MyInterface {
public void DoSomething(){
"Hi I'm B"
}
}
public class MyFactory <TMyInterface> {
void DoSomething(){
TMyInterface.DoSomething()
}
}
The client must remain the same. My question is how can I choose at the server side which implementation of MyInterface to use, by passing the type parameter using .config file in WCF
I read other post but I don't understand yet :(
It is possible to do it, and there are a few ways to do it.
One possibility is to create a "routing" service which will contain the "public" address which the client always talks to. This routing service can then, based on some configuration, redirect the call to the appropriate "real" service.
Another way is to actually have a process which starts both services, but their addresses are defined in config. If you use the same binding and the same contract (which is the case), then you can "flip-flop" the service address when you want to change the service which will receive the calls from the client. For example, this configuration directs the requests to the endpoint at "http://machine-name:8000/Service" to service A. Notice that, since you define service hosts for both services, you actually need to have a base address for service B as well - in this case I used named pipes, which cannot be accessed via different machines.
<system.serviceModel>
<services>
<service name="A">
<host>
<baseAddresses>
<add baseAddress="http://machine-name:8000/Service"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="MyInterface" />
</service>
<service name="B">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/ServiceBackup"/>
</baseAddresses>
</host>
<endpoint address="" binding="netNamedPipeBinding" contract="MyInterface" />
</service>
</services>
</system.serviceModel>
when you want to change the address for B, you'd then swap the addresses.
<system.serviceModel>
<services>
<service name="A">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/ServiceBackup"/>
</baseAddresses>
</host>
<endpoint address="" binding="netNamedPipeBinding" contract="MyInterface" />
</service>
<service name="B">
<host>
<baseAddresses>
<add baseAddress="http://machine-name:8000/Service"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="MyInterface" />
</service>
</services>
</system.serviceModel>
The hosting program would look like this:
public static void HostServices()
{
ServiceHost hostA = new ServiceHost(typeof(A));
ServiceHost hostB = new ServiceHost(typeof(B));
hostA.Open();
hostB.Open();
Console.WriteLine("Press ENTER to close");
Console.ReadLine();
hostA.Close();
hostB.Close();
}
Now, if your services are hosted in IIS (webhost), then it's a little harder. Since the "normal" activation requires a .svc file to be part of the endpoint address, and each .svc file is associated with a single class, the address for A would be something like http://machine-name/services/a.svc while the address for B would be something like http://machine-name/services/b.svc. So what you'd need to do in this case is to create a custom ServiceHostFactory, and use the ASP.NET Routes integration to create a .svc-less URL for your service. Then you'd use something similar to the previous example to decide which service will be activated.