Creating a custom .svc handler for WCF service hosted in IIS - c#

I am hosting a wcf service in IIS 7. I was curious if it would be possible to create my own .svc HttpHandler mapping and class to handle service requests.
For example, if I was to intercept any requests to files that ended with an extension of ".foo" I could add this to my web.config
<handlers>
<add name="*.foo_**" path="*.foo" verb="*" type="MyServer.FooHttpHandler" />
</handlers>
And I could have a class in my default root that did the following
public class FooHandler: IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// do stuff, validate?
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("filename={0}", url));
HttpContext.Current.Response.AddHeader("Content-Type", "fooMimeType");
HttpContext.Current.Response.WriteFile(url);
HttpContext.Current.Response.End();
}
public bool IsReusable
{
get { return false; }
}
}
Is it possible to do something like this with wcf .svc requests? I'm not sure if it'd be the exact same thing or not, since I'm not necessary serving a file to respond with, I want to intercept and proxy the response.
Or is a better way to implement a service behavior that does my required pre-service logic?

What are you trying to achieve? Not sure if you can replace the existing *.svc http handler - but what you can do much more easily is create your own custom ServiceHostFactory for the WCF service. You basically add one attribute your *.svc file:
<%# ServiceHost Language="C#" Debug="true"
Service="YourNamespace.YourService"
Factory="YourNamespace2.YourServiceHostFactory" %>
Using this, IIS will now instantiate your own YourServiceHostFactory and ask you to create an instance of the YourService class. Maybe you can hook into the flow here and do what you need to do?

You could use ASP.NET Routing and an IRouteHandler that returns your own IHttpHandler implementation as well if you really want to as well
http://msdn.microsoft.com/en-us/library/system.web.routing.iroutehandler.gethttphandler.aspx
http://msdn.microsoft.com/en-us/library/cc668201.aspx
I've done this in the past when setting up WCF Data Services and I don't see why it can't work here as well.

Related

Access WebForms ASPX Page Session in ApiController

I am trying to access the Session in Controllers which are part of a webform project. All the session variables are set on ASPX pages
Session["SESSION_KEY_UI_CULTURE"] = ddlLanguage.SelectedValue;
Now on API request from client i need to read Session Variables and perform a task but Session is always null.
[RoutePrefix("api/accounts")]
public class AccountsController : ApiController
{
[Route("config")]
[HttpGet]
public IHttpActionResult GetCompanyConfig()
{
if(HttpContext.Current.Session != null)
{
//Session is always NULL
}
return Ok();
}
}
I have tried removing and adding SessionStateModule in WebConfig file
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
ASP.NET Web Api is meant for REST Services which are by definition stateless. Adding the Session back into Web Api defeats the purpose of having a RESTful API.
You may want to reconsider what you're trying to achieve and find another way to solve your Problem.
But there is a way to do what you want:
To activate Session nontheless add the following to your Global.asax
C#
protected void Application_PostAuthorizeRequest() {
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
VB
Sub Application_PostAuthorizeRequest()
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required)
End Sub
Here and here are 2 Topics that are going into the same direction which you might want to look at for further information

Disable metadata exchange without using web.config

I am developing a single-tenant web application that will be deployed in client data centers and for security reasons we would like to disable the metadata exchange on the applications WCF services. Is it possible to do this this programatically within our service application or another mechanism besides the web.config? We want to prevent more technically minded clients from going to the web.config and turning metadata exchange back on.
You can disable the metadata exchange programmatically by setting the HttpGetEnabled/HttpsGetEnabled to false.
First, Create a derive host from ServiceHost.
public class DerivedHost : ServiceHost
{
public DerivedHost( Type t, params Uri baseAddresses ) :
base( t, baseAddresses )
{
DisableMetadataExchange();
}
private void DisableMetadataExchange()
{
var metadata = Description.Behaviors.Find<ServiceMetadataBehavior>();
if metadata != null)
{
// This code will disable metadata exchange
metadata .HttpGetEnabled = false;
metadata .HttpsGetEnabled = false;
}
}
}
Second, Create a derived factory from ServiceHostFactory.
public class DerivedFactory : ServiceHostFactory
{
public override ServiceHost CreateServiceHost( Type t, Uri[] baseAddresses )
{
return new DerivedHost( t, baseAddresses );
}
}
Third, Create or Edit your your svc file Markup and apply your derived factory.
<% #ServiceHost Factory=”DerivedFactory” Service=”MyService” %>
Fourth, Test your service in the browser and you should see a message contain "Metadata publishing for this service is currently disabled".
If want more details about this implementation kindly visit this link.
Yes. If you code your WCF service as "self describing", which basically means using a WCF intercept layer to handle all the incoming requests to an endpoint, you can just return null from the MEX request.
To make this work is a bit tricky but in my experience leads to a much cleaner implementation than all those voluminous web.config entries. This is described here WCF Configuration without a config file.

How to consume web service via GET methods?

I have a normal 3rd party SOAP service with WSDL and stuff. The problem is - it only accepts GET requests. How can I access it in c#?
When I add that service to VS via Add Service Reference and try to use it as usual:
var service = new BaseSvcClient(
new BasicHttpContextBinding(),
new EndpointAddress("http://some.internal.ip/WebServices/Base.svc"));
var ver = service.Version();
I see (via fiddler) that it actually sends POST requests and web-service responds with Endpoint not found error message.
If I simply hit http://some.internal.ip/WebServices/Base.svc/Version in a browser the proper xml is returned.
I can use WebClient, but then I have to construct all the GET requests manually, which doesn't look good.
Are there other solutions?
I have found an answer that helped me a lot.
Basically if I take an autogenerated interface for the client, decorate methods with [WebGet] and use
var cf = new WebChannelFactory<IBaseSvc2>(new Uri("..."));
var service = cf.CreateChannel();
var result = service.Version();
it all works well. That's not a perfect solution, since changes won't be picked up automatically, so may be there are other solutions?
P.S. an interface for a web service is now like:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName = "BaseService.IBaseSvc")]
public interface IBaseSvc2
{
[System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IBaseSvc/Version", ReplyAction = "http://tempuri.org/IBaseSvc/VersionResponse")]
[WebGet]
VersionInformation Version();
}
You can achieve it by adding the protocols in config file
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>

Sharepoint 2010 does not invoke ProcessRequest of my custom HttpHandler

Well, I know it's IIS which is supposed to invoke it. Anyway; I have a Sharepoint solution which is supposed to return a special string when files with particular extensions are clicked on document libraries.
In the corresponding web.config file I have following to run this HTTP Handler:
<system.webServer>
<handlers>
...
<add name="MyFileHandler" path="*.bar" verb="*" type="Foo.Example.MyHandler, Foo.Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3b53a24010893ac2" resourceType="File" />
...
</handlers>
</system.webServer>
And the HttpHandler class is something like this:
namespace Foo.Example
{
public class MyHandler : IHttpHandler
{
public MyHandler(){} //For breakpoint
public void ProcessRequest(HttpContext context)
{
//Do stuff and write to response.
}
public bool IsReusable
{
get { return false; }
}
}
}
When I try to open a file with '.bar' extension on Sharepoint, it returns 404. What I do in ProcessRequest is not relevant because when I debug the handler, I can see that the handler's constructor is invoked but not the 'ProcessRequest'. Besides the debugger I have also put debug lines(File.AppendAll), again only the constructor gets invoked according to the debug output.
IIS 7.5.7600
Sharepoint 2010 Foundation
Turns out
resourceType="File"
on handler tag in web.config was the problem. Either remove it or set it as "Unspecified".
That is already mentioned here which, unfortunately, I failed to spot before.
The only thing I can think of is to try moving your handler to be really the first one.
Otherwise it could be better to actually integrate with SharePoint instead of trying to override its behavior. In this case you probably should post separate question for what you want to achieve.

How to add SoapExtension attribute to generated web service client proxy without modifying the generated class?

I have created a SoapExtension class to capture the soap request and response from specific web service calls. In order to put this SoapExtension into effect, I have to add an attribute to the method in the generated proxy client.
For example, I've added the AuditSoapCapture attribute to this method:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://blahblah.com/webservices/AddressSearch", RequestNamespace = "http://blahblah.com/webservices/", ResponseNamespace = "http://blahblah.com/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[blahblah.TriadLite.Core.AuditSoapCapture]
public System.Data.DataSet AddressSearch(string HouseNumber, string StreetName, string ZipCode) {
object[] results = this.Invoke("AddressSearch", new object[] {
HouseNumber,
StreetName,
ZipCode});
return ((System.Data.DataSet)(results[0]));
}
I am looking for a way to add this attribute to specific methods without modifying the generated client proxy, as they will get lost when we regenerate. Can I do this in a another partial class or interface or some other way?
Thanks!
Unfortunately, you'll need to modify the proxy code. The other possibilities you mention will not work - a parial class will not overwrite existing functionality, and there is no way that I'm aware of getting an interface to do what you need (compounded by the fact that there is no way to even let the proxy generator know that you intend to implement an interface).
Something that I've done in the past, in a situation where you have access to the source of the webservice, is to write a little app that will parse the code (as text) in the .asmx.cs file of the webservice to extract the names of all the methods that are tagged with [WebMethod]. Then the app "fixes up" the References.cs by inserting appropriate attributes onto the proxied methods, based on some settings file or somesuch. This works well because the naming conventions in the proxy map very neatly to the method names in the original service.
I may just end up injecting my SoapExtension by putting it into the Web.config. This will cause it to be run on every WS call without a client proxy method attribute. Then, I will modify the SoapExtension to look up the called WS method name on a list, and if it is on the list, then do the rest of the SoapExtension logic. I figure the hit on the list in this small volume application isn't going to kill performance.
6 years ago this was posted... So not sure if this will help anyone at this point.
I ran into something similar with a call to an old SOAP web service that had a dynamically generated proxy class that we didn't want to modify as it was auto-generated from the wsdl by the project. In order to solve this problem here is what we did.
The proxy class generated by wsdl.exe is a partial class. We extended this class like so to add a property with the information we wanted to access in the soapextension. You can add as many properties as you want...
partial class mysoapwebservice
{
public string myproperty{ get; set; }
}
in the web.config we registered the soap extension globaly on the project
<webServices>
<soapExtensionTypes>
<add type="MySoapExtension" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
In the code were we created the web service object 'mysoapwebservice' we set the value of the property we needed.
In the soapextension you can get a reference to the web service that was called as well as the values. You can also determine the method call.
`
public class MySoapExtension: SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
{
// web service client object
var webserviceobject= ((SoapClientMessage)message).Client;
// method from web service that was called
var calledMethod = (SoapClientMessage)message).MethodInfo;
// checked the client type of webserviceobject and
//added method / property specific logic here
}
}
}
// other soap extension code
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CriptoExtensionAttribute : SoapExtensionAttribute
[CriptoExtension]
public partial class MainService{

Categories

Resources