Adding an endpoint behavior extension through code - c#

I have a WCF web service, self hosted, configured through the configuration file.
I want to add an endpoint behavior extension to one of my endpoint behaviors programmatically. Adding it through the configuration file is very easy.
<extensions>
<behaviorExtensions>
<add name="EnableCors" type="CorsEnablingExtension.EnableCorsSupportBehaviorElement, CorsEnablingExtension"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="SoapBehavior"/>
<behavior name="RestBehavior">
<CustomBehavior/>
<EnableCors/>
</behavior>
</endpointBehaviors>
</behaviors>
So I can just throw EnableCors in there and everything's fine. But I want to add a delegate parameter in the behavior constructor so I'd like to add it through code, but keep all the other configuration elements.
If I add a static Configure method in my service implementation
public static void Configure(ServiceConfiguration config)
then I have to do all of the configuration programmatically which is too much hassle.
So the question is, can I add that IEndpointBehavior programmatically and keep the rest of the configuration in the config file ?

Related

Adding IClientMessageInspector globally to any service reference

I Have a .net solution with two seperate projects,
one is a class library and other as a web application.
All of my Service References placed in my class library project. and all bindings and endpoint configurations done programmatically.
In my Web Application I Added a IClientMessageInspector and BehaviorExtensionElement by reading this link. How to: Inspect or Modify Messages on the Client
I Don't want to add dbcontext access from within my class library, and all my db operations done at web application project.
Now the problem is I want to log every outgoing service call that place in my class library and I Want to configure this globally. (log to db)
for old style web references I was able to add a Soap Extention like the image below, and all calls logged using TraceExtention class.
I need the same ability using Service References.
You can do the same with WCF by adding behavior extensions to web.config.
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="ClientBehavior">
<ClientEndpointBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="ClientEndpointBehavior" type="Custom.WCFMessageInspector, Custom" />
</behaviorExtensions>
</extensions>
</system.serviceModel>
1- Custom.WCFMessageInspector is where your client inspection code reside.
2- Add behaviorConfiguration="ClientBehavior" to the client endpoint.

Service Only Works While Debugging

I have created a WCF service and am having some trouble testing it once it has been deployed. Here is the PowerShell I am using to test it:
$service = New-WebServiceProxy -Uri http://localhost:16651/Service.svc
$service.GetList()
When debugging the service from Visual Studio with F5, I can call this script without any issue. GetList() returns a long list of telephone numbers.
However, when I host the site on IIS and run the above script, I get an empty return value.
Service Factory
So following this question, I added this attribute to Service.svc:
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"
However, this resulted in my script returning an error on the first line:
New-WebServiceProxy : Object reference not set to an instance of an object.
Which does not make any sense to me, as I am not referencing any empty objects... (this error appears when debugging and when hosting over IIS).
Web.Config
Next, I tried updated my web.config as per the linked question:
<services>
<service name="LyncWebService.Service">
<endpoint binding="webHttpBinding" contract="LyncWebService.IService" behaviorConfiguration="web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
However, now when I try to run my PowerShell script I get this error both during debugging and when hosting on IIS (again on the first line):
The HTML document does not contain Web service discovery information.
I am totally lost here and have no idea what is going wrong. I suspect it is to do with my config file, as it did seem to work when debugging from VS before I messed with the configuration.
Any help or guidance is much appreciated - and please let me know if I can provide any other information or test anything.
Here is the code that makes up my service currently:
Service.svc.cs
namespace LyncWebService
{
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke]
List<string> GetList();
}
public class Service : IService
{
public List<string> GetList()
{
return Ps.GetAssignedNumbers(#"
Set-ExecutionPolicy RemoteSigned
Import-Module Lync
$(Get-CSUser).LineUri"
);
}
}
}
Web.Config
<?xml version="1.0"?>
<configuration>
<appSettings/>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime/>
</system.web>
<system.serviceModel>
<services>
<service name="LyncWebService.Service">
<endpoint binding="webHttpBinding" contract="LyncWebService.IService" behaviorConfiguration="web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<!--<add binding="basicHttpsBinding" scheme="https"/>-->
<add binding="webHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Thanks to Jonathan Coffey, I realised that the service was being run by the LocalSystem account.
After changing this to my own user account and hosting the original web.config on IIS, I am now able to retrieve the full list using my PowerShell script.
Open IIS
Application Pools
Right-Click the Application pool
Advanced Settings...
Process Model -> Identity
Custom Account (Don't forget to include the domain for the User Name!)

Attaching WCF DLL to existing Website

Okay I've created a WCF which I have tested in in IIS and works correctly.
There is a website running, and I've done the following to add this service to that domain:
-Copied the WCF DLL into the website's bin folder.
-Also copied all the DLL this service uses. (Just Newtonsoft.Json)
-Created a new .svc with the following line:
<%# ServiceHost Language="C#" Debug="true" Service="wcfOnScore.OnScoreQuery"%>
-And also added the following to the website's web.config file:
<System.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="WithDebug">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpBinding" scheme="http" />
</protocolMapping>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="0" />
<services>
<service name="wcfOnScore.OnScoreQuery">
<endpoint address="http://www.onscore.co.za/OnScoreQuery.svc"
binding="basicHttpBinding"
listenUri="/"
contract="wcfOnScore.IOnScoreQuery" />
</service>
</services>
</system.serviceModel>
Now this seems to be working. I get the following page when I open it in the browser:
Link To The Screenshot
It is however, not working sadly. I am trying to consume this service from a c# Xamarin android application. It is supposed to return a JSON string. And does this fine when it is hosted locally - This leads me to believe the problem is not in the WCF but the way I am trying to host it.
Anything I might have missed? Or any other alternatives?
Thanks in advance people.
EDIT:
Thought I'd include the error.
"System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation."
The is what the completed eventhandler arguments returns.
Well this an answer to why I get the error, not really a solution. (Yet)
I commented out the Newtonsof.Json using statement. And put in a simple text return which worked.
So from this I deduce that the WCF code can't get its hands on the json.dll.
So it looks like all the above was done correctly if you would like to use as reference. (Except that .dll off course).
If you are trying to return JSON first test it on browser. Your service is SOAP based service because you are using basicHttpBinding. To get result on browser change the binding to WebHttpBinding and add following in your web config.
<endpointBehaviors>
<behavior name="RestBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
If you are able to get response on the browser, you will get response through android also.

WCF .svc worked but not the config file

I am trying to use the configuration file to define endpoint and services information. I have a very simple code that contain OneWay service and a Duplex service. The OneWay worked when I haven't try to alter the configuration file.
Now, I want to use the configuration file to define both service.
Service1 contract name is IOneWayService and the Service2 contract name is ICallBackService.
Both have implemented code in their concrete respective classes name OneWayService.svc.cs and CallBackService.svc.cs.
The configuration file at this moment look like that :
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add relativeAddress="OneWayService.svc" service="TestingWcf.OneWayService"/>
<add relativeAddress="CallBackService.svc" service="TestingWcf.CallBackService"/>
</serviceActivations>
</serviceHostingEnvironment>
<services>
<service name="TestingWcf.OneWayService">
<endpoint address="http://localhost:60847/One"
binding="wsHttpBinding"
contract="IOneWayService" />
</service>
<service name="TestingWcf.CallBackService">
<endpoint address="http://localhost:60847/Two"
binding="wsHttpBinding"
contract="IDuplexService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
I always have this error when trying to execute the OneWayService via this url : http://localhost:60847/OneWayService.svc
The contract name 'IOneWayService'
could not be found in the list of
contracts implemented by the service
'OneWayService'.
Anybody have an idea why?
Edit
I have removed the multipleSiteBindingsEnabled= true from the servinceHostingEnvironment tag and in the contract added the namespace and I could runt the OneWayService.
Also, the Duplex cannot be bound to the wsHttpBinding. I had to change it to NetTcpBinding. But, I had an other error with the Duplex :
Configuration binding extension
'system.serviceModel/bindings/NetTcpBinding'
could not be found. Verify that this
binding extension is properly
registered in
system.serviceModel/extensions/bindingExtensions
and that it is spelled correctly.
From this point, I am lost again.
Edit 2
I did an error in the binding name. I had a capital letter for NetTcpBinding and it does require a lowercase: netTcpBinding. However, it's still not working, now I have:
The protocol 'net.tcp' is not
supported. >.< !!!
OK, that explains it - Visual Studio by default uses the built-in Cassini web server (unless you've already switched to using IIS Express) - and that server doesn't support anything but plain http.
Cassini doesn't support net.tcp and anything like that.
You will need to start using a separate IIS virtual directory and first enable all the necessary support stuff (in the Add/remove Windows Features dialog)

WCF + Wildcard Mapping + IIS6 = 404s on Every Method!

I am receiving 404s when executing a WCF method on IIS6 when wildcard mapping is enabled.
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.
My code is 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').
I've exhausted Google and StackOverflow :(
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

Categories

Resources