溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Spring.Net怎么在MVC中實現注入

發布時間:2021-05-31 18:27:28 來源:億速云 閱讀:148 作者:Leah 欄目:編程語言

本篇文章為大家展示了使用Spring.Net怎么在MVC中實現注入,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

情景

public class HomeController : Controller
  {
    //這是一個很神奇的注入
    private IBLL.IUserInfoService UserInfoService { get; set; }
    public ActionResult Index()
    {
      return Content(UserInfoService.GetName());
    }
  }

每次看代碼都有不一樣的理解,今天我在看MVC控制器中一個通過Spring.Net依賴注入的UserInfoService屬性時,突然有些疑問,注入的前提是控制反轉,這么說我的Controller是從IoC容器中來的了?但是我不記得在哪個地方有配置額,對此我展開了深入的研究。

從MVC本身開始

首先我們要搞懂MVC本身是通過什么方式獲取控制器對象的,本質如果都沒有搞懂,又何來擴展呢?

在MVC模式下,通過實現IControllerFactory接口的對象來獲取當前請求的控制器對象,實現IControllerFactory接口的對象也就是控制器的創建工廠。

簡單看下IControllerFactory

//
  // 摘要:
  //   定義控制器工廠所需的方法。
  public interface IControllerFactory
  {
    //
    // 摘要:
    //   使用指定的請求上下文來創建指定的控制器。
    //
    // 參數:
    //  requestContext:
    //   請求上下文。
    //
    //  controllerName:
    //   控制器的名稱。
    //
    // 返回結果:
    //   控制器。
    IController CreateController(RequestContext requestContext, string controllerName);
    //
    // 摘要:
    //   獲取控制器的會話行為。
    //
    // 參數:
    //  requestContext:
    //   請求上下文。
    //
    //  controllerName:
    //   你想要獲取器其會話行為的控制器的名稱。
    //
    // 返回結果:
    //   控制器的會話行為。
    SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
    //
    // 摘要:
    //   釋放指定的控制器。
    //
    // 參數:
    //  controller:
    //   控制器。
    void ReleaseController(IController controller);
  }

一個Http請求過來,選擇哪個控制器是通過MvcHandler來處理的

控制器工廠是通過ControllerBuilder的Current屬性提供給MvcHandler使用的

下面的代碼是反編譯過來的,簡單看下即可(因為我要標記黃色高亮部分,所以沒有折疊)

internal ControllerBuilder ControllerBuilder
{
  get
  {
    if (this._controllerBuilder == null)
    {
      this._controllerBuilder = ControllerBuilder.Current;
    }
    return this._controllerBuilder;
  }
  set
  {
    this._controllerBuilder = value;
  }
}
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
  // Fields
  private ControllerBuilder _controllerBuilder;
  private static readonly object _processRequestTag;
  internal static readonly string MvcVersion;
  public static readonly string MvcVersionHeaderName;

  // Methods
  static MvcHandler();
  public MvcHandler(RequestContext requestContext);
  protected internal virtual void AddVersionHeader(HttpContextBase httpContext);
  protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state);
  protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state);
  protected internal virtual void EndProcessRequest(IAsyncResult asyncResult);
  private static string GetMvcVersionString();
  protected virtual void ProcessRequest(HttpContext httpContext);
  protected internal virtual void ProcessRequest(HttpContextBase httpContext);
  private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory);
  private void RemoveOptionalRoutingParameters();
  IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
  void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result);
  void IHttpHandler.ProcessRequest(HttpContext httpContext);

  // Properties
  internal ControllerBuilder ControllerBuilder { get; set; }
  public static bool DisableMvcResponseHeader { get; [CompilerGenerated] set; }
  protected virtual bool IsReusable { get; }
  public RequestContext RequestContext { get; [CompilerGenerated] private set; }
  bool IHttpHandler.IsReusable { get; }

  // Nested Types
  [Serializable, CompilerGenerated]
  private sealed class <>c
  {
    // Fields
    public static readonly MvcHandler.<>c <>9;
    public static BeginInvokeDelegate<MvcHandler.ProcessRequestState> <>9__20_0;
    public static EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> <>9__20_1;
    public static Func<KeyValuePair<string, object>, bool> <>9__26_0;

    // Methods
    static <>c();
    public <>c();
    internal IAsyncResult <BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, object asyncState, MvcHandler.ProcessRequestState innerState);
    internal void <BeginProcessRequest>b__20_1(IAsyncResult asyncResult, MvcHandler.ProcessRequestState innerState);
    internal bool <RemoveOptionalRoutingParameters>b__26_0(KeyValuePair<string, object> entry);
  }

  [StructLayout(LayoutKind.Sequential)]
  private struct ProcessRequestState
  {
    internal IAsyncController AsyncController;
    internal IControllerFactory Factory;
    internal RequestContext RequestContext;
    internal void ReleaseController();
  }
}

默認工廠

默認情況下,在ControllerBuilder內部會創建一個DefaultControllerFactory類型的對象,以提供處理請求。

DefaultControllerFactory是實現IControllerFactory接口的。

//
  // 摘要:
  //   表示默認情況下已注冊的控制器工廠。
  public class DefaultControllerFactory : IControllerFactory
  {
    //
    // 摘要:
    //   初始化 System.Web.Mvc.DefaultControllerFactory 類的新實例。
    public DefaultControllerFactory();
    //
    // 摘要:
    //   使用控制器激活器來初始化 System.Web.Mvc.DefaultControllerFactory 類的新實例。
    //
    // 參數:
    //  controllerActivator:
    //   實現控制器激活器接口的對象。
    public DefaultControllerFactory(IControllerActivator controllerActivator);

    //
    // 摘要:
    //   使用指定的請求上下文來創建指定的控制器。
    //
    // 參數:
    //  requestContext:
    //   HTTP 請求的上下文,其中包括 HTTP 上下文和路由數據。
    //
    //  controllerName:
    //   控制器的名稱。
    //
    // 返回結果:
    //   控制器。
    //
    // 異常:
    //  T:System.ArgumentNullException:
    //   requestContext 參數為 null。
    //
    //  T:System.ArgumentException:
    //   controllerName 參數為 null 或為空。
    public virtual IController CreateController(RequestContext requestContext, string controllerName);
    //
    // 摘要:
    //   釋放指定的控制器。
    //
    // 參數:
    //  controller:
    //   要釋放的控制器。
    public virtual void ReleaseController(IController controller);
    //
    // 摘要:
    //   檢索指定請求上下文和控制器類型的控制器實例。
    //
    // 參數:
    //  requestContext:
    //   HTTP 請求的上下文,其中包括 HTTP 上下文和路由數據。
    //
    //  controllerType:
    //   控制器的類型。
    //
    // 返回結果:
    //   控制器實例。
    //
    // 異常:
    //  T:System.Web.HttpException:
    //   controllerType 為 null。
    //
    //  T:System.ArgumentException:
    //   無法分配 controllerType。
    //
    //  T:System.InvalidOperationException:
    //   無法創建 controllerType 的實例。
    protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType);
    //
    // 摘要:
    //   返回控制器的會話行為。
    //
    // 參數:
    //  requestContext:
    //   請求上下文。
    //
    //  controllerType:
    //   控制器的類型。
    //
    // 返回結果:
    //   控制器的會話行為。
    protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType);
    //
    // 摘要:
    //   檢索指定名稱和請求上下文的控制器類型。
    //
    // 參數:
    //  requestContext:
    //   HTTP 請求的上下文,其中包括 HTTP 上下文和路由數據。
    //
    //  controllerName:
    //   控制器的名稱。
    //
    // 返回結果:
    //   控制器類型。
    protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName);
  }

默認情況下,Controller類需要提供默認的構造函數,因為DefaultControllerFactory是通過反射來創建Controller對象實例的。

如果我們定義的Controller需要通過構造函數創建,或者通過某個IoC容器管理Controller,可以通過自定義控制器工廠來實現。

自定義控制器工廠

為什么說這么多關于控制器工廠的東西呢,其實Spring.Net就是通過繼承DefaultControllerFactory創建SpringControllerFactory的。

說了這么多就是為了后面可以更容易的理解Spring.Net的控制器工廠源碼罷了。

回歸正題,接著創建自己的控制器工廠。

1.Home控制器內容如下

public class HomeController : Controller
  {
    private IUserInfoService UserInfoService { get; set; }
    public HomeController(IUserInfoService userInfoService)
    {
      UserInfoService = userInfoService;
    }
    public ActionResult Index()
    {
      return Content(UserInfoService.GetName());
    }
  }

這里的UserInfoService只是一個很簡陋的測試類,只有一個GetName()方法用來返回“小明”。

接下來將通過自定義控制器工廠實現構造注入UserInfoService

2.創建控制器工廠MyControllerFactory

為了方便我直接繼承了DefaultControllerFactory,當然也可以通過實現IControllerFactory來創建

public class MyControllerFactory : DefaultControllerFactory
  {
    private static readonly IBLL.IUserInfoService userInfoService = new BLL.UserInfoService();

    //重寫CreateController
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
      IController controller = null;
      if (controllerName == "Home")
      {
        //如果是我們制定的Home控制器則給其實例化,并通過構造參數注入userInfoService
        controller = new HomeController(userInfoService);
      }
      else
      {
        //通過默認控制器工廠創建控制器
        controller = base.CreateController(requestContext, controllerName);
      }
      return controller;
    }
  }

3.在Global.asax中注冊

protected void Application_Start()
    {
      MyControllerFactory myControllerFactory = new MyControllerFactory();
      //通過ControllerBuilder設置制定的控制器工廠
      ControllerBuilder.Current.SetControllerFactory(myControllerFactory);
      AreaRegistration.RegisterAllAreas();
      RouteConfig.RegisterRoutes(RouteTable.Routes);
    }

4.運行測試(神奇不再神奇)

使用Spring.Net怎么在MVC中實現注入

意料之外,情理之中,我們并沒有在控制器中實例化,結果卻出來了

(實例化在工廠中完成了)

Spring.Net注入原理

說了這么多,回頭看看標題“Spring.Net是怎么在MVC中實現注入的”,你倒是說啊,等的花都謝了,連Spring.Net的毛都沒看到.....

其實,如果你是認真讀過來的,答案在你心中應該已經有了。

答案如下

namespace Spring.Web.Mvc
{
  /// <summary>
  /// Controller Factory for ASP.NET MVC
  /// </summary>
  public class SpringControllerFactory : DefaultControllerFactory
  {
    private static IApplicationContext _context;

    /// <summary>
    /// Gets the application context.
    /// </summary>
    /// <value>The application context.</value>
    public static IApplicationContext ApplicationContext
    {
      get
      {
        if (_context == null || _context.Name != ApplicationContextName)
        {
          if (string.IsNullOrEmpty(ApplicationContextName))
          {
            _context = ContextRegistry.GetContext();
          }
          else
          {
            _context = ContextRegistry.GetContext(ApplicationContextName);
          }
        }

        return _context;
      }
    }

    /// <summary>
    /// Gets or sets the name of the application context.
    /// </summary>
    /// <remarks>
    /// Defaults to using the root (default) Application Context.
    /// </remarks>
    /// <value>The name of the application context.</value>
    public static string ApplicationContextName { get; set; }

    /// <summary>
    /// Creates the specified controller by using the specified request context.
    /// </summary>
    /// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
    /// <param name="controllerName">The name of the controller.</param>
    /// <returns>A reference to the controller.</returns>
    /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext"/> parameter is null.</exception>
    /// <exception cref="T:System.ArgumentException">The <paramref name="controllerName"/> parameter is null or empty.</exception>
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
      IController controller;

      if (ApplicationContext.ContainsObjectDefinition(controllerName))
      {
        controller = ApplicationContext.GetObject(controllerName) as IController;
      }
      else
      {
        controller = base.CreateController(requestContext, controllerName);
      }

      AddActionInvokerTo(controller);

      return controller;
    }

    /// <summary>
    /// Retrieves the controller instance for the specified request context and controller type.
    /// </summary>
    /// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
    /// <param name="controllerType">The type of the controller.</param>
    /// <returns>The controller instance.</returns>
    /// <exception cref="T:System.Web.HttpException">
    ///   <paramref name="controllerType"/> is null.</exception>
    /// <exception cref="T:System.ArgumentException">
    ///   <paramref name="controllerType"/> cannot be assigned.</exception>
    /// <exception cref="T:System.InvalidOperationException">An instance of <paramref name="controllerType"/> cannot be created.</exception>
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
      IController controller = null;

      if (controllerType != null)
      {
        var controllers = ApplicationContext.GetObjectsOfType(controllerType);
        if (controllers.Count > 0)
        {
          controller = (IController)controllers.First().Value;
        }
      }

      if (controller == null)
      {
        //pass to base class for remainder of handling if can't find it in the context
        controller = base.GetControllerInstance(requestContext, controllerType);
      }
      
      AddActionInvokerTo(controller);

      return controller;
    }

    /// <summary>
    /// Adds the action invoker to the controller instance.
    /// </summary>
    /// <param name="controller">The controller.</param>
    protected virtual void AddActionInvokerTo(IController controller)
    {
      if (controller == null)
        return;

      if (typeof(Controller).IsAssignableFrom(controller.GetType()))
      {
        ((Controller)controller).ActionInvoker = new SpringActionInvoker(ApplicationContext);
      }
    }
  }
}

上述內容就是使用Spring.Net怎么在MVC中實現注入,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女