asp.net Web Forms에서 Ninject 또는 DI를 어떻게 구현할 수 있습니까?


83

MVC 응용 프로그램에서 작동하는 데 대한 많은 예제가 있습니다. Web Forms에서 어떻게 수행됩니까?

답변:


79

WebForms에서 Ninject를 사용하는 단계는 다음과 같습니다.

Step1-다운로드

Ninject-2.0.0.0-release-net-3.5 및 WebForm 확장 Ninject.Web_1.0.0.0_With.log4net의 두 가지 다운로드가 필요합니다 (NLog 대안이 있습니다).

웹 응용 프로그램에서 Ninject.dll, Ninject.Web.dll, Ninject.Extensions.Logging.dll 및 Ninject.Extensions.Logging.Log4net.dll 파일을 참조해야합니다.

2 단계-Global.asax

Global 클래스 는 컨테이너를 생성하는 에서 파생 Ninject.Web.NinjectHttpApplication되고 구현되어야 CreateKernel()합니다.

using Ninject; using Ninject.Web;

namespace Company.Web {
    public class Global : NinjectHttpApplication


        protected override IKernel CreateKernel()
        {
            IKernel kernel = new StandardKernel(new YourWebModule());
            return kernel;
        }

StandardKernel생성자는 걸립니다 Module.

3 단계-모듈

이 경우 모듈 YourWebModule은 웹 애플리케이션에 필요한 모든 바인딩을 정의합니다.

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public class YourWebModule : Ninject.Modules.NinjectModule
    {

        public override void Load()
        {
            Bind<ICustomerRepository>().To<CustomerRepository>();
        }   

이 예에서는 ICustomerRepository인터페이스가 참조되는 모든 곳 에서 콘크리트 CustomerRepository가 사용됩니다.

4 단계-페이지

완료되면 각 페이지는 다음에서 상속해야합니다 Ninject.Web.PageBase.

  using Ninject;
    using Ninject.Web;
    namespace Company.Web
    {
        public partial class Default : PageBase
        {
            [Inject]
            public ICustomerRepository CustomerRepo { get; set; }

            protected void Page_Load(object sender, EventArgs e)
            {
                Customer customer = CustomerRepo.GetCustomerFor(int customerID);
            }

InjectAttribute -[Inject]- 주입해서 Ninject를 알려줍니다 ICustomerRepositoryCustomerRepo 속성에.

이미 기본 페이지가있는 경우 Ninject.Web.PageBase에서 파생 할 기본 페이지를 가져 오면됩니다.

5 단계-마스터 페이지

필연적으로 마스터 페이지가 생기고 MasterPage가 삽입 된 개체에 액세스 할 수 있도록하려면 다음에서 마스터 페이지를 파생해야합니다 Ninject.Web.MasterPageBase.

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public partial class Site : MasterPageBase
    {

        #region Properties

        [Inject]
        public IInventoryRepository InventoryRepo { get; set; }     

6 단계-정적 웹 서비스 방법

다음 문제는 정적 메서드에 주입 할 수 없었습니다. 분명히 정적 인 Ajax PageMethod가 몇 개 있었기 때문에 메서드를 표준 웹 서비스로 옮겨야했습니다. 다시 말하지만, 웹 서비스는 Ninject 클래스에서 파생되어야합니다 Ninject.Web.WebServiceBase.

using Ninject;
using Ninject.Web;    
namespace Company.Web.Services
{

    [WebService(Namespace = "//tempuri.org/">http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]    
    [System.Web.Script.Services.ScriptService]
    public class YourWebService : WebServiceBase
    {

        #region Properties

        [Inject]
        public ICountbackRepository CountbackRepo { get; set; }

        #endregion

        [WebMethod]
        public Productivity GetProductivity(int userID)
        {
            CountbackService _countbackService =
                new CountbackService(CountbackRepo, ListRepo, LoggerRepo);

JavaScript에서 . Company.Web.Services.YourWebService.GetProductivity(user, onSuccess)대신 표준 서비스-를 참조해야합니다 PageMethods.GetProductivity(user, onSuccess).

내가 찾은 유일한 다른 문제는 사용자 컨트롤에 개체를 주입하는 것입니다. Ninject 기능을 사용하여 고유 한 기본 UserControl을 만들 수 있지만 필요한 개체에 대한 사용자 정의 컨트롤에 속성을 추가하고 컨테이너 페이지에서 속성을 설정하는 것이 더 빠릅니다. 기본적으로 UserControls를 지원하는 것이 Ninject "할 일"목록에 있다고 생각합니다.

Ninject를 추가하는 것은 매우 간단하며 뛰어난 IoC 솔루션입니다. 많은 사람들이 Xml 구성이 없기 때문에 좋아합니다. Ninject 구문을 사용하여 객체를 Singleton으로 변환하는 것과 같은 다른 유용한 "트릭"이 Bind<ILogger>().To<WebLogger>().InSingletonScope()있습니다. WebLogger를 실제 Singleton 구현으로 변경할 필요가 없습니다.


1
이것은 치료법이 작동하지만 새로운 WebForms 앱 (템플릿에서)에서 이것을 시도한 결과 Global.asax.cs 파일에 기본 세션 메서드 (예 : Application_Start)가있을 때 앱이 암호 오류를 반환하는 것을 발견했습니다. (NinjectHttpApplication에서 구현되었으므로) 삭제해야 할 필요가 있다는 것이 분명 할 수 있지만 나를 잡았습니다.
Matt

도움이되었다 니 다행입니다. 오류가 이상하게 들립니다. 예외는 무엇입니까? Application_Start에 코드가 있으며 제대로 작동합니다.
Joe Ratzer 2011 년

3
Global.asax.cs 파일의 Application_Start 메서드에서 슈퍼 타입의 메서드 NinjectHttpApplication.Application_Start를 호출하는 것을 잊었습니다. 그렇게하면 작동하고, 그렇지 않으면 고장났습니다.
매트

1
물론 지금 작업중인 애플리케이션에는 기본 페이지가 있습니다 (항상 좋은 생각). PageBase를 구현할 기본 페이지 만 가져옵니다.
조 Ratzer

2
지금은 구식 인 것 같습니다. NuGet 패키지 인 ninject.web에는 앱을 부트 스트랩하기위한 일부 코드가 포함되어있어 NinjectHttpApplication에서 직접 상속해야 할 필요가 없습니다.
RyanW

68

Ninject v3.0 (2012 년 4 월 12 일 기준)의 출시로 더 쉬워졌습니다. 주입은 HttpModule을 통해 구현되므로 페이지가 사용자 정의 페이지 / 마스터 페이지에서 상속받을 필요가 없습니다. 빠른 스파이크를위한 단계 (및 코드)는 다음과 같습니다.

  1. 새 ASP.NET WebForms 프로젝트 만들기
  2. NuGet을 사용하여 Ninject.Web lib를 추가합니다 (Ninject.Web.Common 및 Ninject libs도 중단됨).
  3. App_Start / NinjectWebCommon.cs / RegisterServices 메서드에 사용자 지정 바인딩을 등록합니다.
  4. 페이지에 속성 삽입 사용

NinjectWebCommon / RegisterServices

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IAmAModel>().To<Model1>();
    } 

기본

public partial class _Default : System.Web.UI.Page
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
    }
}

Site.Master

public partial class SiteMaster : System.Web.UI.MasterPage
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("From master: " 
            + Model.ExecuteOperation());
    }
}

모델

public interface IAmAModel
{
    string ExecuteOperation();         
}

public class Model1 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 1";
    }
}

public class Model2 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 2";
    }
}

출력 창 결과

I am a model 1
From master: I am a model 1

안녕하세요 제이슨 ... 구현하려고합니다 ... NuGet에서 Ninject.Web lib를 가져 왔습니다 ... App_Start에 부트 스트 래퍼를 생성했습니다. 디버깅 할 RegisterServices에 중단 점을 추가하려고했지만 거기에 도달하지 못했습니다. ... 다른 것을 추가해야합니까?
Paul

1
@Paul Debugger.Break ()를 RegisterServices 메서드에 넣어 디버깅을 시작할 수 있습니다.
Boggin

5
안녕하세요 제이슨. 이 작업을 수행하는 데 문제가 있으므로 이것이 완전한 요약인지 궁금합니다. NinjectHttpModule이 런타임에로드되었지만 주입이 발생하지 않는 것을 볼 수 있습니다. 이것이 사실이어야하는 이유를 생각할 수 있습니까?
rusmus

3
좋은 예 감사합니다. 페이지 / 마스터 페이지에서는 작동하지만 Asmx에서는 작동하지 않습니다. Asmx에서 어떻게 작동하도록 할 수 있습니까? 감사.
lawphotog 2014

1
@mreyeros 확실히 당신이이 있는지 확인 NinjectWeb.csApp_Start. Ninject를 초기화하는 코드는이 파일에 있어야합니다. 별도의 파일에있는 경우 (예 : NinjectWebCommon.cs작동하지 않음). NuGet을 사용하여 Ninject.Web을 다른 Ninject 패키지보다 나중에 설치하는 경우 발생할 수 있습니다.
nebffa

12

여기에 대한 대답은 현재 열린 버그 로 인해 작동하지 않습니다 . 다음은 ninject 클래스에서 상속 할 필요없이 고객 httpmodule을 사용하여 페이지 및 컨트롤에 삽입하는 @Jason 단계의 수정 된 버전입니다.

  1. 새 ASP.NET WebForms 프로젝트 만들기
  2. NuGet을 사용하여 Ninject.Web lib 추가
  3. App_Start / NinjectWebCommon.cs / RegisterServices 메서드에 사용자 지정 바인딩을 등록합니다.
  4. InjectPageModule을 추가하고 NinjectWebCommon에 등록하십시오.
  5. 페이지에 속성 삽입 사용

InjectPageModule.cs

 public class InjectPageModule : DisposableObject, IHttpModule
{
    public InjectPageModule(Func<IKernel> lazyKernel)
    {
        this.lazyKernel = lazyKernel;
    }

    public void Init(HttpApplication context)
    {
        this.lazyKernel().Inject(context);
        context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
    }

    private void OnPreRequestHandlerExecute(object sender, EventArgs e)
    {
        var currentPage = HttpContext.Current.Handler as Page;
        if (currentPage != null)
        {
            currentPage.InitComplete += OnPageInitComplete;
        }
    }

    private void OnPageInitComplete(object sender, EventArgs e)
    {
        var currentPage = (Page)sender;
        this.lazyKernel().Inject(currentPage);
        this.lazyKernel().Inject(currentPage.Master);
        foreach (Control c in GetControlTree(currentPage))
        {
            this.lazyKernel().Inject(c);
        }

    }

    private IEnumerable<Control> GetControlTree(Control root)
    {
        foreach (Control child in root.Controls)
        {
            yield return child;
            foreach (Control c in GetControlTree(child))
            {
                yield return c;
            }
        }
    }

    private readonly Func<IKernel> lazyKernel;
}

NinjectWebCommon / RegisterServices

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IHttpModule>().To<InjectPageModule>();
        kernel.Bind<IAmAModel>().To<Model1>();

    } 

기본

public partial class _Default : System.Web.UI.Page
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
    }
}

Site.Master

public partial class SiteMaster : System.Web.UI.MasterPage
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("From master: " 
            + Model.ExecuteOperation());
    }
}

모델

public interface IAmAModel
{
    string ExecuteOperation();         
}

public class Model1 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 1";
    }
}

public class Model2 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 2";
    }
}

출력 창 결과

I am a model 1
From master: I am a model 1

4
마스터 페이지가없는 페이지에서는 실패합니다. 나는 이것으로 NinjectWebCommon을 수정했습니다 : if (currentPage.Master!=null) { this.lazyKernel().Inject(currentPage.Master); }
H.Wolper

1
시간을내어 문서화 해 주셔서 감사합니다. 레거시 웹 양식 프로젝트에서 동일한 문제가 발생했습니다. 덕분에 너무 늦게 호출되었지만 그렇지 않으면 완벽하기 때문에 Page_Init 이전에 작업하도록 정렬되었습니다. 감사합니다 @ 아담!
PoorbandTony

이 솔루션은 나에게 정말 무작위적인 문제를 일으켰습니다. 예를 들어 OnCommand 이벤트는 Repeater 내의 LinkButton에서 실행을 중지했습니다. 그래도 모든 코드 숨김 이벤트를 중단하지는 않았습니다.
Mike Cole

8

ASP.NET Web Forms에서 Ninject.Web을 구현하는 단계는 다음과 같습니다.

  1. Global.asax에서 NinjectHttpApplication을 구현합니다. 커널의 경우 NinjectModule을 구현하여 전달합니다.
  2. 코드 뒤에있는 각 웹 양식 페이지로드 이벤트에서 Ninject.Web.PageBase를 구현합니다. 그 위에 [Inject] 필터가있는 인스턴스 클래스를 추가합니다.

더 자세한 예를 보려면 아래에 몇 가지 유용한 링크가 있습니다.

1. http://joeandcode.net/post/Ninject-2-with-WebForms-35

2. http://davidhayden.com/blog/dave/archive/2008/06/20/NinjectDependencyInjectionASPNETWebPagesSample.aspx


1
이것은 당신이 정확히해야 할 일인 Ninject.Web 확장을 추가했다고 가정합니다.
Dave Thieben

7
@nellbryant이 두 링크 모두 이제 작동하지 않습니다.
Boggin 2012 년

joeandcode.net 링크는 이제 죽었습니다. 보관 된 버전은 여기에 있습니다 : web.archive.org/web/20160324142135/http://joeandcode.net/post/…
Chris Walsh

4

Ninject.Web 확장을 살펴보십시오. 기본 인프라 https://github.com/ninject/ninject.web을 제공합니다.


5
내가 예를 들어야한다는 것을 알고 있지만 README는> 0 바이트 여야합니다!
Ruben Bartelink

@Ruben : 문서 업데이트가 atm 목록에서 가장 중요한 작업 중 하나라는 데 동의합니다.
Remo Gloor

2
우선 순위와 커뮤니티에서 얼마나 많은 도움을 받는지에 관한 것입니다. 작년에 많은 문서가 추가되었습니다. 다음과 같은 이유로 다른 기능보다 덜 중요하다고 생각하기 때문에 Ninject.Web에는 적합하지 않습니다. a) WebForms는 구식입니다. 대신 MVC를 사용합니다. 다른 사람들과 마찬가지로 코드에서이 확장에 대한 지식을 얻어야합니다. c) 나는 그것을 직접 사용하지 않는다-나보다 문서를 훨씬 더 잘 작성할 수있는 다른 사람들이있다. 그러나 그것은 그들 중 누구에게도 중요하지 않은 것 같습니다. 나의 여가 시간은 당신과 같이 제한되어 있으므로 모든 것을 할 수는 없습니다.
Remo Gloor 2012

6
문서 누락 때문에 @RyanW Downvoting은 실제로 내 동기를 높이 거나이 문서를 작성하는 우선 순위를 높이 지 않습니다!
Remo Gloor 2012

1
@RyanW 어디에서 아이디어를 얻습니까? 나는 1 년 전의 비꼬는 댓글에 대해 기분이 좋지 않지만 a) 찬성표를 동반했습니다. b) 비꼬는 것이었지만 우는 것은 아닙니다. Remo가 장난감을 버리는 것을 선호하는 완전히 합법적 인 점을 반박하십시오. BTW 나는 Unity가 멋진 문서를 가지고 있고 당신의 골목길에 더 가깝다고 확신합니다. 그리고 nellbryant 또는 Jor R의 답변을 살펴보고 결함을 찾거나 readme 또는 샘플을 직접 작성하는 데 사용하십시오.
Ruben Bartelink 2012

0

Steve Sanderson (Apress)의 "Pro ASP.NET MVC 2 Framework, 2nd Edition"책을 확인하십시오. 저자는 Ninject를 사용하여 데이터베이스에 연결합니다. 예제를 사용하고 필요에 맞게 조정할 수 있다고 생각합니다.


네, 그 질문을하게 만든 것이 있습니다. 웹 애플리케이션이 웹 양식 인 경우 어떻게 수행됩니까?
nellbryant

이것은 또한 일반적으로 WebForms에서 수행하는 방법입니다. 트릭은 커널의 Get 메서드를 사용해야한다는 것입니다.
Didaxis

0
public IGoalsService_CRUD _context { get; set; }

_context 개체는 어떻게 든 null로 설정됩니다. 다음은 나머지 설정입니다.

public partial class CreateGoal : Page
{
    [Inject]
    public IGoalsService_CRUD _context { get; set; }
}

글로벌 파일의 경우

protected override IKernel CreateKernel()
{
    IKernel kernel = new StandardKernel(new Bindings());
    return kernel;
}

public class Bindings : NinjectModule
{
    public override void Load()
    {
        Bind<goalsetterEntities>().To<goalsetterEntities>();
        Bind<IGoalsService_CRUD>().To<GoalsService_CRUD>();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.