Is it possible to create a "drop-in" web service? What I would like to do is create an .svc file that can be placed into a web directory on IIS and accessed (and executed) via its URL, without having to install any other files and without changing any configuration files.
I am investigating a possible security problem in a web application that allows uploading .svc files. If it is possible to upload and then execute an .svc file, this would be a big security problem for this application. Unfortunately I am not a .NET developer, so I am probably missing a lot of things here.
I know that it is possible to put the service interface and implementation straight into the the .svc file after the "Service Host" directive. Here is my .svc file:
<%@ ServiceHost La开发者_如何学Cnguage = "C#" Debug = "true" Service = "EchoService" %>
public interface IEchoService
{
string Hello();
}
public class EchoService : IEchoService
{
public string Hello()
{
return "Hello";
}
}
Now when I access http://localhost/test1.svc I get an exception from .NET: Service 'EchoService' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.
I understand that normally you are supposed to configure web service end points in web.config or app.config file. From some Googling I have also learned that it is possible to configure endpoints programmatically by defining your own ServiceHost and ServiceCodeFactory. I have found some examples, but couldn't get them working.
I would really appreciate if somebody can either tell me "No, what you are trying to do is impossible, because..." or show how I can add the necessary code to the example above to have an executable service.
Update: using Josh's suggestion I finally got it working. See my answer below for the working code.
Okay, I got a working SOAP web service contained in an .svc file. Here is the code:
<%@ ServiceHost
Language = "C#"
Debug = "true"
Factory="Hello.CustomServiceHostFactory"
Service = "Hello.HelloService" %>
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace Hello
{
public class CustomServiceHostFactory : ServiceHostFactory
{
public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
return base.CreateServiceHost(constructorString, baseAddresses);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
CustomHost host = new CustomHost(serviceType, baseAddresses);
//configure customServiceHost here
host.AddServiceEndpoint(typeof(IHelloService), new BasicHttpBinding(), "");
var smb = host.Description.Behaviors.Find <System.ServiceModel.Description.ServiceMetadataBehavior>();
if(smb == null)
{
// add the "get metadata" behavior
// This will allow the service to emit WSDL when tickled at the right HTTP endpoint
smb= new System.ServiceModel.Description.ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
}
return host;
}
}
public class CustomHost : ServiceHost
{
public CustomHost()
{
}
public CustomHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
public CustomHost(object singeltonInstance, params Uri[] baseAddresses)
: base(singeltonInstance, baseAddresses)
{
}
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
}
}
[ServiceContract(Namespace="http://www.example.com")]
public interface IHelloService
{
[OperationContract]
string Hello();
}
public class HelloService : IHelloService
{
public string Hello() {
return "Hello";
}
}
}
It works on .NET 4, not sure about the previous versions.
I've never done this before myself, but a possible solution would be to have a ServiceHost
factory. I believe (without trying it myself) you can programatically configure the ServiceHost through the methods exposed by using a custom service host.
http://msdn.microsoft.com/en-us/library/bb332338.aspx
Scroll down to Accessing ServiceHost in IIS
Listing 5-6. .svc file with a CustomServiceHostFactory
<% @ServiceHost Language="C#" Debug="true"
Service="QuickReturns.StockTrading.ExchangeService.TradeService"
Factory="QuickReturns.StockTrading.ExchangeService.
TradeServiceCustomHostFactory" %>
Listing 5-7. TradeServiceCustomHostFactory and TradeServiceCustomHost
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace QuickReturns.StockTrading.ExchangeService
{
public class TradeServiceCustomHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType, Uri[] baseAddresses)
{
TradeServiceCustomHost customServiceHost =
new TradeServiceCustomHost(serviceType, baseAddresses);
//configure customServiceHost here
return customServiceHost;
}
}
public class TradeServiceCustomHost : ServiceHost
{
public TradeServiceCustomHost(Type serviceType, params Uri[]
baseAddresses)
: base(serviceType, baseAddresses)
{
//or configure here
}
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
}
}
}
You might be able to drop all of that into one svc.
精彩评论