上次已经获取了Controller的名字,想通过Controller的名字来实例化一个Controller,该怎么办呢?
MVC框架的做法是从相关的Assembly中找出所有符合Controller特性的类型。将它们放入一个叫MVC-ControllerTypeCache.xml的缓存中。这次重点我们来仿真一下如何从所有先关的Assembly中找出Controller类型,缓存机制到以后性能优化再详细叙述。
IController.cs:
namespace MvcFake.mvc
{
public interface IController
{
}
}
HomeController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcFake.mvc;
namespace MvcFake.Controllers
{
public class HomeController : IController
{
}
}
MvcHandler.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Collections;
using System.IO;
using System.Web.Compilation;
using System.Reflection;
namespace MvcFake.mvc
{
public class MvcHandler : IHttpHandler
{
public bool IsReusable { get; set; }
private RequestContext RequestContext { get; set; }
public MvcHandler(RequestContext requestContext)
{
RequestContext = requestContext;
}
internal static bool IsControllerType(Type t)
{
return
t != null &&
t.IsPublic &&
t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
!t.IsAbstract &&
typeof(IController).IsAssignableFrom(t);
}
private static bool TypeIsPublicClass(Type type)
{
return (type != null && type.IsPublic && type.IsClass && !type.IsAbstract);
}
private static IEnumerable<Type> FilterTypesInAssemblies()
{
IEnumerable<Type> typesSoFar = Type.EmptyTypes;
ICollection assemblies = BuildManager.GetReferencedAssemblies();
foreach (Assembly assembly in assemblies)
{
Type[] typesInAsm;
try
{
typesInAsm = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
typesInAsm = ex.Types;
}
typesSoFar = typesSoFar.Concat(typesInAsm);
}
return typesSoFar.Where(type => TypeIsPublicClass(type) && IsControllerType(type));
}
public void ProcessRequest(HttpContext context)
{
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
context.Response.Write("Controller Name: " + controllerName);
IEnumerable<Type> types = FilterTypesInAssemblies();
foreach (var type in types)
{
context.Response.Write("<br>Controller Type Name: " + type.ToString());
}
}
}
}
项目结构:
运行程序:
从运行的结果可以看到,我们已经成功地找到Assembly中的Controller了。