ControllerFactory for specific portable area

≡放荡痞女 提交于 2019-12-03 15:26:14

You can use a MasterControllerFactory that contains all the IControllerFactory implementations for each area, and knows which factory can build which RequestContext. This actually allows you to select a different ControllerFactory for any variation, not just by area. Here's how it works:

All of the area controller factory implementations must implement IFilteredControllerFactory instead of IControllerFactory. Here it is:

public interface IFilteredControllerFactory:IControllerFactory
{
    bool CanHandle(RequestContext requestContext);
}  

An example of an implementation that filters based on the area name looks like this:

public class Area51ControllerFactory:IFilteredControllerFactory
{
    public bool CanHandle(RequestContext requestContext)
    {
        return requestContext.RouteData.DataTokens["area"].ToString().ToLowerInvariant() == "area51";
    }
    public IController CreateController(RequestContext requestContext, string controllerName)
    {
        // create a controller...
    }

    public void ReleaseController(IController controller)
    {
        // release the controller...
    }

}

Then you need the MasterControllerFactory, which looks like this:

public class MasterControllerFactory : DefaultControllerFactory
{
    private readonly List<IFilteredControllerFactory> _slaveFactories;
    public MasterControllerFactory()
    {
        _slaveFactories = new List<IFilteredControllerFactory>();
    }
    public void RegisterFactory(IFilteredControllerFactory slaveFactory)
    {
        if(slaveFactory!=null && !_slaveFactories.Contains(slaveFactory))
        {
            _slaveFactories.Add(slaveFactory);
        }
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var factory = _slaveFactories.FirstOrDefault(x => x.CanHandle(requestContext));
        if(factory!=null)
        {
            return factory.CreateController(requestContext, controllerName);
        }
        return base.CreateController(requestContext, controllerName);
    }

    public override void ReleaseController(IController controller)
    {
        bool released = false;
        if (controller is Controller)
        {
            var requestContext = ((Controller) controller).ControllerContext.RequestContext;
            var factory = _slaveFactories.FirstOrDefault(x => x.CanHandle(requestContext));
            if (factory != null)
            {
                factory.ReleaseController(controller);
                released = true;
            }
        }
        if(!released)base.ReleaseController(controller);
    }
}

In the Application_Start of your global.asax you still need to set everything up, but that's easy.

var masterControllerFactory = new MasterControllerFactory();
masterControllerFactory.Register(new Area51ControllerFactory());
ControllerBuilder.Current.SetControllerFactory(masterControllerFactory);

Obviously, you can tweak this a number of ways to work best with your coding style and application architecture.

Andrew Savinykh

I don't think you can have different factory per area, but you can in your single factory, put the controller into different container, based on the area. I think but not sure, that you can find your area in CreateController method of your factory by querying this:

requestContext.RouteData.DataTokens["area"];

where requestContext is passed to CreateController as a parameter.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!