Инъекция зависимостей ASMX и IoC - PullRequest
16 голосов
/ 21 октября 2011

Так что я застрял при попытке заставить мой веб-сервис asmx использовать внедрение зависимостей и использовать IoC для этого.Я хочу, чтобы мой веб-сервис мог использовать мои внутренние сервисы бизнес-уровня.Веб-сервис должен использоваться внешним клиентом из другого домена и в основном будет использоваться для отправки и получения информации о таких объектах, как Заказы и Клиенты.

Примером может быть:

public class MyService : System.Web.Services.WebService
{
    [WebMethod]
    public string HelloWorld()
    {
        return new MyBusinessService().MyMethod();
    } 
}

public class MyBusinessService : IMyBusinessService
{
    public string MyMethod()
    {
        return "hello";
    }
}

Я хочу использовать внедрение зависимостей, чтобы устранить необходимость «обновления» моего сервиса, но я не могу найти способ сделать это.Я могу заставить его работать, используя DI для бедных, или, по крайней мере, я думаю, что это называется «бедняги».

вот так:

public class MyService : System.Web.Services.WebService
{
    private IMyBusinessService _myService;

    public MyService(IMyBusinessService myService)
    {
        _myService = myService;
    }

    public MyService() : this(new MyBusinessServie()) { }

    [WebMethod]
    public string HelloWorld()
    {
        return _myService.MyMethod();
    }
}

Но я просто не могу понять, какиспользовать контейнер IoC для внедрения моих зависимостей, потому что я не могу заставить службу работать без конструктора без параметров.Пожалуйста, будьте добры, я не опытный программист и только что начал тестировать внедрение зависимостей и заставил его нормально работать в моем приложении для Windows Form с Structuremap, но застрял на этом.

Ответы [ 2 ]

35 голосов
/ 28 февраля 2012

К сожалению, в ASP.NET нет способа внедрить конструктор с помощью веб-сервисов.ASP.NET требует, чтобы вы предоставили конструктор по умолчанию.Конструктор MyService примерно настолько близок к корню композиции, который вы можете получить с помощью этого типа веб-службы, без использования контейнера DI.

В ASP.NET нет ничего необычного в том, чтобы иметь несколько корней композиции.Которые могут быть конструкторами отдельных веб-сервисов и веб-страниц.Если вы используете ASP.NET MVC, то это ControllerFactory, более дружественный к DI.

В вашей реализации важная часть не состоит в том, чтобы перенести построение графа объектов из веб-службы, так как этокорень вашей композиции.Главное, чтобы веб-служба была максимально тонкой, сохраняла большую часть логики в зависимости, чтобы ее можно было протестировать или использовать повторно.Извлечение информации из заголовков HTTP является примером задачи, которую веб-служба может затем передать этой информации в зависимость.

Хорошей книгой для ссылок на шаблоны и методы DI является ЗависимостьИнъекция в .NET от Mark Seemann.

Если в вашем веб-сервисе вместо System.Web.Services.WebService реализован System.Web.IHttpHandler, вы можете реализовать свой DI следующим образом:

Global.ashx.cs

public class Global : HttpApplication
{
    protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        var context = ((HttpApplication)sender).Context;

        var needsMyBusinessService = context.Handler as INeedMyBusinessService;
        if (needsMyBusinessService != null)
            needsMyBusinessService.MyBusinessService = new MyBusinessService();
    }
}

MyService.ashx.cs

public class MyService : IHttpHandler, INeedMyBusinessService
{
    public IMyBusinessService MyBusinessService { get; set; }

    public bool IsReusable { get { return true; } }

    public void ProcessRequest(HttpContext context)
    {
        // uses my dependency
    }
}

INeedMyBusinessService.cs

public interface INeedMyBusinessService
{
    IMyBusinessService MyBusinessService { get; set; }
}

Однако выгода с этой реализацией заключается в том, что не работает с веб-службами, которые реализуют System.Web.Services.WebService, поскольку объект веб-службы не инициализируется до тех пор, пока не будет вызвано событие PreRequestHandlerExecute, то есть последнее событие перед вызовом ProcessRequest.

ВышеПример работает, если вы хотите иметь уникальный экземпляр для каждого веб-сервиса.Если вы хотите иметь один и тот же экземпляр (жизненный цикл Singleton) MyBusinessService для каждого запроса веб-службы, вы можете реализовать файл Global.ashx.cs следующим образом:

public class Global : HttpApplication
{
    private static IMyBusinessService businessService;

    protected void Application_Start(object sender, EventArgs e)
    {
        Global.businessService = new MyBusinessService();
    }

    protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        var context = ((HttpApplication)sender).Context;

        var needsMyBusinessService = context.Handler as INeedMyBusinessService;
        if (needsMyBusinessService != null)
            needsMyBusinessService.MyBusinessService = Global.businessService;
    }
}
1 голос
/ 14 июня 2018

В WebService может быть только конструктор без параметров.Однако то, что вы могли бы сделать, это иметь свойство класса WebService, а внутри конструктора без параметров вызывать что-то вроде _myDependency = container.resolve ();

...