I am working on a windows service to host WCF services for various projects. Using the following app.config fragment:
<system.serviceModel>
<services>
<service name="MyWcfService" behaviorConfiguration="MetaDataBehavior">
<endpoint contract="MyWcfService" binding="wsHttpBinding" address="" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetaDataBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</bindings>
</system.serviceModel>
I can expose the stock service "help" page and a WSHttpBinding on the same URL from within my service like so:
ServiceHost myServiceHost = new ServiceHost(typeof(MyWcfService), new Uri(serviceAddress));
myServiceHost.Open()
I can then open a web browser and go to, e.g. http://host:8001/services/MyWcfService, and I see the standard WCF help page so I know the service is working. (For the moment, let's ignore the security implications of exposing the help page.) I can also access the WSHttpBinding endpoint on the same URL.
We have now grown to host a lot of WCF services within this service, so I'm working to simplify the configuration by adding endpoints programatically to the ServiceHost object. This all works just fine using myServiceHost.AddServiceEndpoint().
The last piece I haven't been able to get programatically is enabling the ServiceDebug behavior on the same URL as the WSHttpBinding. I have the following:
ServiceDebugBehavior sdb = myServiceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
if (sdb == null)
{
sdb = new ServiceDebugBehavior()
{
HttpHelpPageEnabled = true,
IncludeExceptionDetailInFaults = true
};
myServiceHost.Description.Behaviors.Add(sdb);
}
else
{
sdb.HttpHelpPageEnabled = true;
sdb.IncludeExceptionDetailInFaults = true;
//sdb.HttpHelpPageUrl = new Uri(serviceAddress +"/help");
}
ServiceEndpoint endpoint = new ServiceEndpoint(contract, new WSHttpBinding, new EndpointAddress(new Uri(serviceAddress)));
myServiceHost.AddServiceEndpoint(endpoint);
which works, so long as I a) change the address of the help page (as commented above), or b) change the URI on which the WSHttpBinding listens. Conceptually this makes sense: .NET doesn't want to have two endpoints listening on the same URI.
My problem is that I have to maintain compatibility with existing applications using this service, which means my endpoint addresses cannot change. If I can accomplish this through the app.config, why can I not accomplish this programatically?
You can't actually ADD a ServiceDebugBehavior to a ServiceHost, what you have to do is modify the existing ServiceDebugBehavior (was having the same issue)
Example
svcHost = new ServiceHost(typeof(MyService), adrbase);
// Configure Your Service
// Now for the ServiceDebugBehavior you want to modify (Example disable HTTP Help Page)
svcHost.Description.Behaviors.Find<ServiceDebugBehavior>().HttpHelpPageEnabled = false;
Related
I have a Net Framework 4.5 WCF Service, running with async/task methods. It is deployed on a valid URL, with a correct Digicert certificate, assuring the domain. We have a "client certificate", with a "one-to-one" mapping, and all its ok for our "Winforms" apps.
Now, we wan't to call it from our Android/iOS Xamarin projects.
We know that Xamarin doesn't supports wsBinding, so we're are using this config:
Server
<system.serviceModel>
<services>
<service
name="serviceWCF.nameService"
behaviorConfiguration="behavior_base">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="transport"
contract="serviceWCF.nameInterfaceService" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="transport">
<security mode="Transport" >
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="behavior_base">
<serviceMetadata httpsGetEnabled="true" httpsGetUrl=""/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
We created a proxy from SVCUTIL.EXE, then we have implement manually the async methods, channel creation, because Xamarin doesn't supports dinamic bindings, and so on.
The proxy for our Xamarin client app, it's invoked so:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
AddressHeader addressHeader2;
AddressHeader[] addressHeaders;
EndpointAddress endpoint;
addressHeader2 = AddressHeader.CreateAddressHeader("nameapp_iOS", "https:\\URL_WCF_Service.svc", 0);
addressHeaders = new AddressHeader[]{ addressHeader2};
endpoint = new EndpointAddress(new System.Uri("https:\\URL_WCF_Service.svc"),addressHeaders);
System.Security.Cryptography.X509Certificates.X509Certificate2 oCert;
oCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(System.IO.File.ReadAllBytes("CertBundle.pfx"), "pass");
Service_MovilClient oProxy = new Service_MovilClient(binding, endpoint);
Service_MovilClient oProxy.ClientCredentials.ClientCertificate.Certificate = oCert
But ... nothing happens... time out....
The server it's ok. The url can be accessed from the iOS emulator. We can use it with only "basicHttpBinding", but, we want to use SSL+Client Certificate.
Any ideas? Now I'm stuck.
It's worthless to spoil more efforts. By now, WCF Xamarin its very short.
I have to settle for with HTTPs and a basic Transport Security (security mode="Transport").
I have to use that Wcf services ... But if you, pathetic human, are reading this prior a new development, use REST services. They have a much better support form Xamarin.
I write c# code, to dynamic connect to WCF server. If connect will less that 1 minutes it's work perfect. But if remote function work more than 1-2 minutes, it's throw exception. This is my code:
try
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding()
{
CloseTimeout = TimeSpan.FromMinutes(20),
OpenTimeout = TimeSpan.FromMinutes(20),
ReceiveTimeout = TimeSpan.FromMinutes(10),
SendTimeout = TimeSpan.FromMinutes(10)
};
EndpointAddress endpointAddress = new EndpointAddress("http://***");
IBrowserClicker personService = new ChannelFactory<IBrowserClicker>(basicHttpBinding, endpointAddress).CreateChannel();
Console.WriteLine(personService.TestConnect().Equals("Hello google!"));
}
catch (Exception exception)
{
Console.WriteLine("Error:"+exception);
}
Exception:
Error:System.ServiceModel.FaultException: The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.
So, how it's fix?
try to turn on IncludeExceptionDetailInFaults in web.config file to see the exact error. and this is possible duplicate of
Turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server
This explain as follows, and it worked for me.
In your .config file define a behavior:
<configuration>
<system.serviceModel>
<serviceBehaviors>
<behavior name="debug">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
...
Then apply the behavior to your service along these lines:
<configuration>
<system.serviceModel>
...
<services>
<service name="MyServiceName" behaviorConfiguration="debug">
</services>
</system.serviceModel>
</configuration>
Please look at it and let me know if you find trouble to activate it.
I have a REST WCF service defined as follows:
[ServiceContract]
public interface IRest {
[OperationContract]
[WebGet(UriTemplate = "/test")]
int Test();
}
With the following web.config:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="ServiceX.RestBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceX.RestBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
<services>
<service behaviorConfiguration="ServiceX.RestBehavior"
name="ServiceX.Rest">
<endpoint address="" behaviorConfiguration="ServiceX.RestBehavior"
binding="webHttpBinding" contract="ServiceX.IRest" />
</service>
</services>
</system.serviceModel>
All works fine without wildcard mapping; I can browse to '/services/rest.svc/test' and I'll receive the expected result.
However, as soon as I enable wildcard mapping (.* > C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll), then I start receiving 404s when I attempt to access a method (although I can still view '/services/rest.svc').
Any ideas? I've exhausted Google and StackOverflow. No-one seems to be sharing this problem :(
EDIT: You can all reproduce this by creating a new WCF Service in VS2008 (new Project > WCF Service Application). Browse to the dummy method ('GetData')... you will notice it returns 400... that's fine because it shows it's still forwarding to WCF. However, if you enable wildcard mapping in IIS6 you will now get a 404, meaning WCF is no longer intercepting the request.
I just had the same problem with a WCF service running on IIS6.
I could browse the service on http://someurl/service.svc, but I would get a 404 when hitting a method on the service such as http://someurl/service.svc/somemethod.
The fix, in my case, was easy. The .svc file type was configured in IIS to be handled by C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll, but my service was running in a ASP.NET v4.0 apppool, so I simply pointed the .svc file type to be handled by C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll
In the popup dialog where you specify the path for the wildcard mapping, there is check box for a setting called 'Verify that file exists'. This setting needs to be turned off.
If it is not turned off, you will get a 404 (page not found)
I've have a WCF service which has multiple clients that it connects to.
What I want to do is to create the clients dynamically the WCF services consumes.
Creating the clients by inheriting from the ServiceFactory<TChannel> class is done and very simple. What I'm struggling with is how to read Endpoint behaviours from the web.config file and add them to the clients?
Code file
BasicHttpBinding binding = new BasicHttpBinding(bindingConfigName);
EndpointAddress endpoint = new EndpointAddress(endpointUrl);
ChannelFactory<IShoppingSoap> clientEndpoint = new ChannelFactory<IShoppingSoap>(binding, endpoint);
base.Endpoint.Behaviors.Add(*Get the behavior from the config file*);
return base.CreateChannel();
Web.config file :
<behaviors>
<endpointBehaviors>
<behavior name="EndpointBehaviour_GmCustom">
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
<behavior>
</endpointBehaviors>
</behaviors>
Found the solution.. i think.. you have to go through each of the operations in the endpoint and change the maxItemsInObjectGraph there.
foreach (OperationDescription operation in base.Endpoint.Contract.Operations)
{
operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 2147483646;
}
Found the solution here
http://www.lapathy.com/home/2009/9/30/programmatically-setting-maxitemsinobjectgraph-in-wcf.html
I am having some trouble hosting a WCF service inside a Windows Service.
I can start my WCF service in VS2008 and by navigating to the base address in my app.config
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="WCF.IndexerBehavior"
name="WCF.Indexer">
<endpoint address="" binding="wsHttpBinding" contract="WCF.IIndexer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/WCFService/Action/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF.IndexerBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I can see it works fine, I get the page saying I created a service and code samples on how to use it are shown.
Now my next step was to create a Windows Service to host my WCF shown above.
I just used te windows service template, it gave me a Program.cs and Service1.cs which I renamed to WindowsServiceHost.cs. In it I have:
private ServiceHost host;
public WindowsServiceHost()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
var serviceType = typeof(Indexer.WCF.Indexer);
host = new ServiceHost(serviceType);
host.Open();
}
catch (Exception ex)
{
}
}
protected override void OnStop()
{
if (host != null)
{
host.Close();
}
}
Everything compiles fine, I can run InstallUtil (I defined an installer).
The service used to start and stop immediately but disabling Windows Defender got rid of this.
Now the service starts (As a network service) and stays up (I think), but when I navigate to the base address, I get the not found page.
Another weird thing is when I try to stop the service (which is still displayed as running) I get:
Error 1061: The service cannot accept control messages at this time
I've tried everything but am at a loss.
Not 100% sure what the reason really is - just to confirm, we self-host WCF services in Windows services all the time and it generally works perfectly fine.
Two points you could try - just to get a feeling for the behavior and a potential clue for the problem:
1) I notice you open the ServiceHost with just the type of the service - that works, but you might still want to add a base address even to the call of the new ServiceHost() - like this:
host = new ServiceHost(serviceType,
new Uri("http://localhost:8181/WCFService/Action/");
Can you navigate to that address and get the service page??
2) The other thing I noticed is that your service seems to be called Indexer.WCF.Indexer as specified in the typeof() before opening the host, but in the config file, the name= on the <service> tag is only "WCF.Indexer".
Could you possibly try to change that tag to read:
<service behaviorConfiguration="WCF.IndexerBehavior"
name="Indexer.WCF.Indexer">
Does that help? Are you now able to see the service page when navigating to it in the browser?
Marc
Self-hosting HTTP in a Windows service may require registering the endpoint with HttpCfg.exe. Take a look here.
Try removing the catch statement, there may be an error that you are not seeing