WCF Reading Endpoint Behaviors from a web.config file - c#

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

Related

Dynamic WCF client doesn't wait more than one minute

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.

How to programatically add ServiceDebug behavior with endpoint?

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;

Return image from WCF web service

I have created my first WCF webservice and I am trying to return an image from it based on some passed parameters. I am getting the error:
The content type image/jpeg of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly.
What do I need to do to resolve this issue?
The web.config file of my website that is calling the service has the following config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IRestImageService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:59473/RestImageService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IRestImageService"
contract="RestImageService.IRestImageService" name="BasicHttpBinding_IRestImageService" />
</client>
The webservice web.config looks like this:
<system.serviceModel>
<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>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
The Service Contract:
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "Image/{type}/{typeid}/{imageid}/{size}/{extension}",
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped)]
Stream Image(string type, string typeid, string imageid, string size = "lrg", string extension = "jpg");
I am very new at WCF, so any help/pointers would be greatly appreciated!
Update
After implementing Tim's suggestion, I am getting a new error:
There was no endpoint listening at localhost:59473/RestImageService.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
I am not sure how to configure the web service to fix this issues. Any suggestions?
This is how I'm accessing the web service:
RestImageServiceClient client = new RestImageServiceClient();
client.Image(WSC.Common.BO.User.User.ImageFolder.Buyer, "27085", "BuyerPhoto", "LRG", "jpg");
I hope to be able to set the src tag of my image to the web service url once I get it working.
basicHttpBinding is SOAP (version 1.1). To enable REST-based services, I believe (haven't done much of it myself) that you need to use the webHttpBinding.
I would try something like this. In your service's config file, make the following changes:
<protocolMapping>
<add binding="webHttpBinding" scheme="http"/>
</protocolMapping>
This should configure your default binding to be webHttpBinding for http calls.
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
<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>
The above code should add a default endpoint behavior for webHttp.
Finally, in your client config file, make the following change:
<client>
<endpoint address="http://localhost:59473/RestImageService.svc"
binding="webHttpBinding"
contract="RestImageService.IRestImageService"
name="WebHttpBinding_IRestImageService" />
</client>
I can't say for certain that this will work, but I've done a lot with WCF (on the SOAP side), so I think this will at least get you pointed in the right direction.
EDIT
RestImageServiceClient is a SOAP client. To use a REST service, you need to use an HTTP API. Here's an example from [WCF REST Service with JSON]http://www.codeproject.com/Articles/327420/WCF-REST-Service-with-JSON):
WebClient client = new WebClient();
byte[] data = client.DownloadData("http://localhost:11523/Service1.svc/GetData");
Stream stream = new MemoryStream(data);
DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(string));
string result = obj.ReadObject(stream).ToString();
I recommend googling "WCF REST JSON Client exmaple" - you'll get lots of hits and a few different ways to do this.
As an added note, you could make a SOAP call with your SOAP client, as long as you have a SOAP endpoint exposed on the service.

WCF Methods Return 404 When Wildcard Mapping Is Enabled In IIS6

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)

Invalid Operation Exception

I created a WCF Serice that worked fine when hosted on IIS.
now, I took the same service, and created a host application in WPF, and when trying to start the service from that application, I get this exception :
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.
The error is quite clear - you're using HTTP, you have enabled HttpGetEnabled on your ServiceMetadata behavior, but you have not provided a base address in your config.
In IIS, base addresses are neither needed, nor used, since the location of the *.svc file defines your service address. When you're self-hosting, you can and should use base addresses.
Change your config to look something like this:
<system.serviceModel>
<services>
<service name="YourService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/YourService" />
</baseAddresses>
</host>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" />
..... (your own other endpoints) ...........
</service>
</services>
</system.serviceModel>
Now, the "HttpGetEnabled" has a base address http://localhost.8080/YourService to go to to get the metadata from.
Or if you don't like this, again, the error message is quite clear on your alternative: define an absolute URL for the HttpGetUrl in your ServiceMetadata:
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata
httpGetEnabled="true"
httpGetUrl="http://localhost:8282/YourService/mex" />
</behavior>
</serviceBehaviors>
The clients can get your metadata from your "mex" endpoints, either at a fixed URL defined as in this second example, or they will go to the base address of the service for the metadata (if there is one).
If you're coming from IIS and haven't adapted anything, you'll have neither a base address, nor an explicit, absolute URL for your Metadata exchange endpoint, so that's why you get the error you're seeing.
Marc
I faced this error when I tried to use net.pipe binding.In my case, the default service behavior published the service metadata, This is the cause of my error. My solution is to use different behavior for your services. , then I changed my config file according to #marc_s answer and make different service behaviors as follows:
<serviceBehaviors>
<!--Default behavior for all services (in my case net pipe binding)-->
<behavior >
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<!--for my http services -->
<behavior name="MyOtherServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
Check that the service class is correct.
It's solved my problem
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(ServiceClass));

Categories