ServicesContainer是一个服务的容器,可以理解为—个轻量级的IoC容器,其维护着一个服务接口类型与服务实例之间的映射关系,可以根据服务接口类型获取对应的服务实例。构成ASP.NET Web API核心框架的消息处理管道的每个环节都注册了相应的组件来完成某项独立的任务,这些 “标准化 ”的组件—般都实现了某个预定义的接口,如果这些原生的组件不能满足我们的需求,我们完全可以通过实现相应的接口创建自定义的组件,然后以某种形式将它们 “注册安装 ”到消息处理管道上。

  ASP.NET Web API的 配置都是通过HttpConfiguration来完成的,自定义 “服务实例 ”的注册也是由它来完成,有一个类 型为 ServicesContainer的只读属性Sewice,默认使用的 ServicesContainer是 一个类型为 Defaultservices的对象.

一、涉及的类和源码分析

1、ServicesContainer 

  抽象类,用IEnumerable<object>或List<object>及其子类存放服务实例集合,具体用哪种类型由其子类来决定。提供了对服务类型的服务实例的添加,删除,查询,覆盖,查找,还有可以标记是否是单服务实例,如GetService,GetServices,Add,FindIndex,Replace等方法,公开了几个抽象接口,如下边的抽象方法,由子类实现。

public abstract class ServicesContainer : IDisposable
{
internal readonly Lazy<IExceptionLogger> ExceptionServicesLogger;
internal readonly Lazy<IExceptionHandler> ExceptionServicesHandler; protected ServicesContainer()
{
ExceptionServicesLogger = new Lazy<IExceptionLogger>(CreateExceptionServicesLogger);
ExceptionServicesHandler = new Lazy<IExceptionHandler>(CreateExceptionServicesHandler);
}
//抽象方法,获取某个接口类型对应的实例类型
public abstract object GetService(Type serviceType); //抽象方法,获取某个接口类型的对应的多个实例类型
public abstract IEnumerable<object> GetServices(Type serviceType); //抽象方法,获取某个接口类型的对应的多个实例类型
protected abstract List<object> GetServiceInstances(Type serviceType);
//虚方法清空某个服务类型的缓存
protected virtual void ResetCache(Type serviceType)
{
} //服务类型是单实例还是多实例
public abstract bool IsSingleService(Type serviceType); //往某个服务接口的服务实例列表末尾添加一个服务实例
public void Add(Type serviceType, object service)
{
Insert(serviceType, Int32.MaxValue, service);
} //往某个服务接口的服务实例列表末尾添加多个服务实例
public void AddRange(Type serviceType, IEnumerable<object> services)
{
InsertRange(serviceType, Int32.MaxValue, services);
} //移除服务类型的所有服务实例,分单实例和多实例情况
public virtual void Clear(Type serviceType)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
} if (IsSingleService(serviceType))
{
ClearSingle(serviceType);
}
else
{
ClearMultiple(serviceType);
}
ResetCache(serviceType);
} //抽象方法,清除单实例
protected abstract void ClearSingle(Type serviceType); //清除多实例
protected virtual void ClearMultiple(Type serviceType)
{
List<object> instances = GetServiceInstances(serviceType);
instances.Clear();
} //根据匹配的委托查找符合条件的第一个索引位置(从0开始),找不到就返回-1
public int FindIndex(Type serviceType, Predicate<object> match)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
if (match == null)
{
throw Error.ArgumentNull("match");
} List<object> instances = GetServiceInstances(serviceType);
return instances.FindIndex(match);
} //在服务类型的服务实例集合的指定索引位置(0开始)插入一个服务实例
public void Insert(Type serviceType, int index, object service)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
if (service == null)
{
throw Error.ArgumentNull("service");
}
if (!serviceType.IsAssignableFrom(service.GetType()))
{
throw Error.Argument("service", SRResources.Common_TypeMustDriveFromType, service.GetType().Name, serviceType.Name);
} List<object> instances = GetServiceInstances(serviceType);
if (index == Int32.MaxValue)
{
index = instances.Count;
} instances.Insert(index, service); ResetCache(serviceType);
} //在服务类型的服务实例集合的指定索引位置(0开始)插入多个服务实例
public void InsertRange(Type serviceType, int index, IEnumerable<object> services)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
if (services == null)
{
throw Error.ArgumentNull("services");
} object[] filteredServices = services.Where(svc => svc != null).ToArray();
object incorrectlyTypedService = filteredServices.FirstOrDefault(svc => !serviceType.IsAssignableFrom(svc.GetType()));
if (incorrectlyTypedService != null)
{
throw Error.Argument("services", SRResources.Common_TypeMustDriveFromType, incorrectlyTypedService.GetType().Name, serviceType.Name);
} List<object> instances = GetServiceInstances(serviceType);
if (index == Int32.MaxValue)
{
index = instances.Count;
} instances.InsertRange(index, filteredServices); ResetCache(serviceType);
} //从服务类型的服务实例列表中移除指定的服务实例
public bool Remove(Type serviceType, object service)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
if (service == null)
{
throw Error.ArgumentNull("service");
} List<object> instances = GetServiceInstances(serviceType);
bool result = instances.Remove(service); ResetCache(serviceType); return result;
} //移除某个服务类型的所有委托匹配的服务实例元素
public int RemoveAll(Type serviceType, Predicate<object> match)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
if (match == null)
{
throw Error.ArgumentNull("match");
} List<object> instances = GetServiceInstances(serviceType);
int result = instances.RemoveAll(match); ResetCache(serviceType); return result;
} //移除某个服务类型的服务实例集合的指定索引的服务实例
public void RemoveAt(Type serviceType, int index)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
} List<object> instances = GetServiceInstances(serviceType);
instances.RemoveAt(index); ResetCache(serviceType);
} //用某个服务实例替换某个服务类型所有的服务实例
public void Replace(Type serviceType, object service)
{
// 更早的空检查,不需要在插入之前就调用RemoveAll,而导致空服务异常
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
} if ((service != null) && (!serviceType.IsAssignableFrom(service.GetType())))
{
throw Error.Argument("service", SRResources.Common_TypeMustDriveFromType, service.GetType().Name, serviceType.Name);
} if (IsSingleService(serviceType))
{
ReplaceSingle(serviceType, service);
}
else
{
ReplaceMultiple(serviceType, service);
}
ResetCache(serviceType);
}
//抽象方法,替换单个实例
protected abstract void ReplaceSingle(Type serviceType, object service); protected virtual void ReplaceMultiple(Type serviceType, object service)
{
//先移除所有,再在头部插入
RemoveAll(serviceType, _ => true);
Insert(serviceType, , service);
} //用多个服务实例替换某个服务类型所有的服务实例
public void ReplaceRange(Type serviceType, IEnumerable<object> services)
{
if (services == null)
{
throw Error.ArgumentNull("services");
} RemoveAll(serviceType, _ => true);
InsertRange(serviceType, , services);
}
//资源回收空实现,子类重写
public virtual void Dispose()
{
} private IExceptionLogger CreateExceptionServicesLogger()
{
return ExceptionServices.CreateLogger(this);
} private IExceptionHandler CreateExceptionServicesHandler()
{
return ExceptionServices.CreateHandler(this);
}
}

 2、DefaultServices 

  继承自ServicesContainer,是默认实现,在HttpConfiguration里指定,构造函数中注册一些默认的实例,注意点:

  • 使用到了IDependencyResolver进行DI操作获取实例
  • 使用了缓存提高性能,ConcurrentDictionary

  另外,两个核心方法逻辑  

  • GetService,重写方法,根据服务类型获取单个服务实例,缓存里有就从缓存里,否则把DI解析,如果有就返回,否则从字典里获取返回,并添加进缓存
  • GetServices,重写方法,根据服务类型获取服务实例列表,缓存里有就从缓存里,否则把DI解析的和字典里的一起返回,,并添加进缓存
 public class DefaultServices : ServicesContainer
{
//缓存
private ConcurrentDictionary<Type, object[]> _cacheMulti = new ConcurrentDictionary<Type, object[]>();
private ConcurrentDictionary<Type, object> _cacheSingle = new ConcurrentDictionary<Type, object>();
private readonly HttpConfiguration _configuration; //服务实例存放集合
private readonly Dictionary<Type, object> _defaultServicesSingle = new Dictionary<Type, object>();
private readonly Dictionary<Type, List<object>> _defaultServicesMulti = new Dictionary<Type, List<object>>();
//通过它来
private IDependencyResolver _lastKnownDependencyResolver;
private readonly HashSet<Type> _serviceTypesSingle;
private readonly HashSet<Type> _serviceTypesMulti; /// <summary>
/// This constructor is for unit testing purposes only.
/// </summary>
protected DefaultServices()
{
} private void SetSingle<T>(T instance) where T : class
{
_defaultServicesSingle[typeof(T)] = instance;
}
private void SetMultiple<T>(params T[] instances) where T : class
{
var x = (IEnumerable<object>)instances;
_defaultServicesMulti[typeof(T)] = new List<object>(x);
} public DefaultServices(HttpConfiguration configuration)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
} _configuration = configuration; //初始化注册服务类型的服务实例,即使是空的,获得空会抛异常 SetSingle<IActionValueBinder>(new DefaultActionValueBinder());
SetSingle<IApiExplorer>(new ApiExplorer(configuration));
SetSingle<IAssembliesResolver>(new DefaultAssembliesResolver());
SetSingle<IBodyModelValidator>(new DefaultBodyModelValidator());
SetSingle<IContentNegotiator>(new DefaultContentNegotiator());
SetSingle<IDocumentationProvider>(null); // Missing SetMultiple<IFilterProvider>(new ConfigurationFilterProvider(),
new ActionDescriptorFilterProvider()); SetSingle<IHostBufferPolicySelector>(null);
SetSingle<IHttpActionInvoker>(new ApiControllerActionInvoker());
SetSingle<IHttpActionSelector>(new ApiControllerActionSelector());
SetSingle<IHttpControllerActivator>(new DefaultHttpControllerActivator());
SetSingle<IHttpControllerSelector>(new DefaultHttpControllerSelector(configuration));
SetSingle<IHttpControllerTypeResolver>(new DefaultHttpControllerTypeResolver());
SetSingle<ITraceManager>(new TraceManager());
SetSingle<ITraceWriter>(null); // This is a priority list. So put the most common binders at the top.
SetMultiple<ModelBinderProvider>(new TypeConverterModelBinderProvider(),
new TypeMatchModelBinderProvider(),
new KeyValuePairModelBinderProvider(),
new ComplexModelDtoModelBinderProvider(),
new ArrayModelBinderProvider(),
new DictionaryModelBinderProvider(),
new CollectionModelBinderProvider(),
new MutableObjectModelBinderProvider());
SetSingle<ModelMetadataProvider>(new DataAnnotationsModelMetadataProvider());
SetMultiple<ModelValidatorProvider>(new DataAnnotationsModelValidatorProvider(),
new DataMemberModelValidatorProvider()); // This is an ordered list,so put the most common providers at the top.
SetMultiple<ValueProviderFactory>(new QueryStringValueProviderFactory(),
new RouteDataValueProviderFactory()); ModelValidatorCache validatorCache = new ModelValidatorCache(new Lazy<IEnumerable<ModelValidatorProvider>>(() => this.GetModelValidatorProviders()));
SetSingle<IModelValidatorCache>(validatorCache); SetSingle<IExceptionHandler>(new DefaultExceptionHandler());
SetMultiple<IExceptionLogger>(); _serviceTypesSingle = new HashSet<Type>(_defaultServicesSingle.Keys);
_serviceTypesMulti = new HashSet<Type>(_defaultServicesMulti.Keys); // Reset the caches and the known dependency scope
ResetCache();
} public override bool IsSingleService(Type serviceType)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
return _serviceTypesSingle.Contains(serviceType);
} //重写方法,根据服务类型获取单个服务实例,缓存里有就从缓存里,否则把DI解析,如果有就返回,否则从字典里获取返回,并添加进缓存
public override object GetService(Type serviceType)
{
// 为空直接抛出异常,提高性能
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
} // 如果DependencyResolver改变了,缓存里解析的变为无效,要清空
if (_lastKnownDependencyResolver != _configuration.DependencyResolver)
{
ResetCache();
} object result;
//在缓存里直接返回
if (_cacheSingle.TryGetValue(serviceType, out result))
{
return result;
} // Check input after initial read attempt for performance.
if (!_serviceTypesSingle.Contains(serviceType))
{
throw Error.Argument("serviceType", SRResources.DefaultServices_InvalidServiceType, serviceType.Name);
} //从DI获取服务实例,为了不实例化多次,放到缓存
object dependencyService = _lastKnownDependencyResolver.GetService(serviceType);
//不在缓存里(肯定不在),添加到缓存,并设置结果
if (!_cacheSingle.TryGetValue(serviceType, out result))
{
//如果DI获取到,就用它,否则就从字典中获取
result = dependencyService ?? _defaultServicesSingle[serviceType];
_cacheSingle.TryAdd(serviceType, result);
} return result;
} //重写方法,根据服务类型获取服务实例列表,缓存里有就从缓存里,否则把DI解析的和字典里的一起返回,,并添加进缓存
public override IEnumerable<object> GetServices(Type serviceType)
{
// 为空直接抛出异常,提高性能
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
} // 如果DependencyResolver改变了,缓存里解析的变为无效,要清空
if (_lastKnownDependencyResolver != _configuration.DependencyResolver)
{
ResetCache();
} object[] result; if (_cacheMulti.TryGetValue(serviceType, out result))
{
return result;
} // Check input after initial read attempt for performance.
if (!_serviceTypesMulti.Contains(serviceType))
{
throw Error.Argument("serviceType", SRResources.DefaultServices_InvalidServiceType, serviceType.Name);
} //从DI获取服务实例,为了不实例化多次,放到缓存
IEnumerable<object> dependencyServices = _lastKnownDependencyResolver.GetServices(serviceType);
//不在缓存里(肯定不在),添加到缓存,并设置结果
if (!_cacheMulti.TryGetValue(serviceType, out result))
{
//把DI中获取的和字典中获取的一起放到结果中
result = dependencyServices.Where(s => s != null)
.Concat(_defaultServicesMulti[serviceType])
.ToArray();
_cacheMulti.TryAdd(serviceType, result);
} return result;
} //重写方法,返回某个服务类型的所有服务实例
protected override List<object> GetServiceInstances(Type serviceType)
{
Contract.Assert(serviceType != null); List<object> result;
if (!_defaultServicesMulti.TryGetValue(serviceType, out result))
{
throw Error.Argument("serviceType", SRResources.DefaultServices_InvalidServiceType, serviceType.Name);
} return result;
} //重写方法,清除单个
protected override void ClearSingle(Type serviceType)
{
_defaultServicesSingle[serviceType] = null;
} //重写方法 替换某个
protected override void ReplaceSingle(Type serviceType, object service)
{
if (serviceType == null)
{
throw Error.ArgumentNull("serviceType");
}
_defaultServicesSingle[serviceType] = service;
} //移除所有缓存
private void ResetCache()
{
_cacheSingle = new ConcurrentDictionary<Type, object>();
_cacheMulti = new ConcurrentDictionary<Type, object[]>();
_lastKnownDependencyResolver = _configuration.DependencyResolver;
} //重写方法 移除某个服务的缓存
protected override void ResetCache(Type serviceType)
{
object single;
_cacheSingle.TryRemove(serviceType, out single);
object[] multiple;
_cacheMulti.TryRemove(serviceType, out multiple);
}
}

 3、HttpConfiguration

 

public class HttpConfiguration : IDisposable
{
private readonly HttpRouteCollection _routes;
private readonly ConcurrentDictionary<object, object> _properties = new ConcurrentDictionary<object, object>();
private readonly MediaTypeFormatterCollection _formatters;
private readonly Collection<DelegatingHandler> _messageHandlers = new Collection<DelegatingHandler>();
private readonly HttpFilterCollection _filters = new HttpFilterCollection();
//IDependencyResolver
private IDependencyResolver _dependencyResolver = EmptyResolver.Instance;
private Action<HttpConfiguration> _initializer = DefaultInitializer;
private bool _initialized; private bool _disposed; public HttpConfiguration()
: this(new HttpRouteCollection(String.Empty))
{
} public HttpConfiguration(HttpRouteCollection routes)
{
if (routes == null)
{
throw Error.ArgumentNull("routes");
} _routes = routes;
_formatters = DefaultFormatters(this);
//使用DefaultServices
Services = new DefaultServices(this);
ParameterBindingRules = DefaultActionValueBinder.GetDefaultParameterBinders();
} //内部设置
public ServicesContainer Services { get; internal set; }
}

4、ServicesExtensions

  ServicesContainer扩展方法,方便调用,调用具体的某个服务类型的服务实例,空判断,抛异常。

 public static class ServicesExtensions
{
public static IEnumerable<ModelBinderProvider> GetModelBinderProviders(this ServicesContainer services)
{
return services.GetServices<ModelBinderProvider>();
} public static ModelMetadataProvider GetModelMetadataProvider(this ServicesContainer services)
{
return services.GetServiceOrThrow<ModelMetadataProvider>();
} public static IEnumerable<ModelValidatorProvider> GetModelValidatorProviders(this ServicesContainer services)
{
return services.GetServices<ModelValidatorProvider>();
} internal static IModelValidatorCache GetModelValidatorCache(this ServicesContainer services)
{
return services.GetService<IModelValidatorCache>();
} public static IContentNegotiator GetContentNegotiator(this ServicesContainer services)
{
return services.GetService<IContentNegotiator>();
} public static IHttpControllerActivator GetHttpControllerActivator(this ServicesContainer services)
{
return services.GetServiceOrThrow<IHttpControllerActivator>();
} public static IHttpActionSelector GetActionSelector(this ServicesContainer services)
{
return services.GetServiceOrThrow<IHttpActionSelector>();
} public static IHttpActionInvoker GetActionInvoker(this ServicesContainer services)
{
return services.GetServiceOrThrow<IHttpActionInvoker>();
} public static IActionValueBinder GetActionValueBinder(this ServicesContainer services)
{
return services.GetService<IActionValueBinder>();
} public static IEnumerable<ValueProviderFactory> GetValueProviderFactories(this ServicesContainer services)
{
return services.GetServices<ValueProviderFactory>();
} public static IBodyModelValidator GetBodyModelValidator(this ServicesContainer services)
{
return services.GetService<IBodyModelValidator>();
} public static IHostBufferPolicySelector GetHostBufferPolicySelector(this ServicesContainer services)
{
return services.GetService<IHostBufferPolicySelector>();
} public static IHttpControllerSelector GetHttpControllerSelector(this ServicesContainer services)
{
return services.GetServiceOrThrow<IHttpControllerSelector>();
} public static IAssembliesResolver GetAssembliesResolver(this ServicesContainer services)
{
return services.GetServiceOrThrow<IAssembliesResolver>();
} public static IHttpControllerTypeResolver GetHttpControllerTypeResolver(this ServicesContainer services)
{
return services.GetServiceOrThrow<IHttpControllerTypeResolver>();
} public static IApiExplorer GetApiExplorer(this ServicesContainer services)
{
return services.GetServiceOrThrow<IApiExplorer>();
} public static IDocumentationProvider GetDocumentationProvider(this ServicesContainer services)
{
return services.GetService<IDocumentationProvider>();
} public static IExceptionHandler GetExceptionHandler(this ServicesContainer services)
{
return services.GetService<IExceptionHandler>();
} public static IEnumerable<IExceptionLogger> GetExceptionLoggers(this ServicesContainer services)
{
return services.GetServices<IExceptionLogger>();
} public static IEnumerable<IFilterProvider> GetFilterProviders(this ServicesContainer services)
{
return services.GetServices<IFilterProvider>();
} public static ITraceManager GetTraceManager(this ServicesContainer services)
{
return services.GetService<ITraceManager>();
} public static ITraceWriter GetTraceWriter(this ServicesContainer services)
{
return services.GetService<ITraceWriter>();
} internal static IEnumerable<TService> GetServices<TService>(this ServicesContainer services)
{
if (services == null)
{
throw Error.ArgumentNull("services");
} return services.GetServices(typeof(TService)).Cast<TService>();
} // 通用的泛型方法,空判断,抛异常
private static TService GetService<TService>(this ServicesContainer services)
{
if (services == null)
{
throw Error.ArgumentNull("services");
} return (TService)services.GetService(typeof(TService));
} private static T GetServiceOrThrow<T>(this ServicesContainer services)
{
T result = services.GetService<T>();
if (result == null)
{
throw Error.InvalidOperation(SRResources.DependencyResolverNoService, typeof(T).FullName);
} return result;
}
}

 二、自定义组件扩展

  扩展:

 public class ExtendedDefaultAssembliesResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
PreLoadedAssembliesSettings settings = PreLoadedAssembliesSettings.GetSection();
if (null != settings)
{
foreach (AssemblyElement element in settings.AssemblyNames)
{
AssemblyName assemblyName = AssemblyName.GetAssemblyName(element.AssemblyName);
if (!AppDomain.CurrentDomain.GetAssemblies() .Any(assembly => AssemblyName.ReferenceMatchesDefinition(assembly.GetName(), assemblyName)))
{
AppDomain.CurrentDomain.Load(assemblyName);
}
}
}
return base.GetAssemblies();
}
}

  注册:

 httpServer.Configuration.Services.Replace(typeof(IAssembliesResolver),new ExtendedDefaultAssembliesResolver());

ASP.NET Web API 框架研究 服务容器 ServicesContainer的更多相关文章

  1. ASP.NET Web API 框架研究 IoC容器 DependencyResolver

    一.概念 1.IoC(Inversion of Control),控制反转 即将依赖对象的创建和维护交给一个外部容器来负责,而不是应用本身.如,在类型A中需要使用类型B的实例,而B的实例的创建不是由A ...

  2. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  3. ASP.NET Web API 框架研究 Action方法介绍

    在根据请求解析出匹配的Controller类型并创建实例后,要在该Controller类型中的众多Action方法中选择与请求匹配的那一个,并执行,然后返回响应. Action方法,其元数据,主要包括 ...

  4. ASP.NET Web API 框架研究 Controller实例的销毁

    我们知道项目中创建的Controller,如ProductController都继承自ApiController抽象类,其又实现了接口IDisposable,所以,框架中自动调用Dispose方法来释 ...

  5. ASP.NET Web API 框架研究 Self Host模式下的消息处理管道

    Self Host模式下的ASP.NET Web API与WCF非常相似,都可以寄宿在任意类型的托管应用程序中,宿主可以是Windows Form .WPF.控制台应用以及Windows Servic ...

  6. ASP.NET Web API 框架研究 核心的消息处理管道

    ASP.NET Web API 的核心框架是一个由一组HttpMessageHandler有序组成的双工消息处理管道:寄宿监听到请求接受后,把消息传入该管道经过所有HttpMessageHandler ...

  7. ASP.NET Web API 框架研究 Web Host模式下的消息处理管道

    寄宿的作用是开启一个进程为Web API提供一个运行环境以解决持续监听.请求监听和响应回复,即将接收到的请求转换成HttpRequestMessage对象传入管道,并将管道生成并经过处理后的HttpR ...

  8. ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道

    Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...

  9. ASP.NET Web API 框架研究 ASP.NET 路由

    ASP.NET Web API 如果采用Web Host方式来寄宿,在请求进入Web API 消息处理管道之前,就会用ASP.NET 自身的路由系统根据注册的路由表,解析出当前请求的HttpContr ...

随机推荐

  1. dpdk中文文档

    Linux平台上DPDK入门指南 1. 简介 1.1. 文档地图 2. 系统要求 2.1. X86 上预先设置 BIOS 2.2. 编译DPDK 2.3. 运行DPDK应用程序 3. 使用源码编译DP ...

  2. vs视图引入命名空间设置方法

    解决: 1.@using在cshtml的最上面,加上一句: @using Puzzle.Framework.Common 2.在View文件夹下面的web.config里面加: <system. ...

  3. Servlet会话管理三(HttpSession)

    Session是服务器端技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的HttpSession对象.由于Session为浏览器用户所独享,所以用户在访问服务器的web资源时,可以把各自的数 ...

  4. Spring 系列教程之自定义标签的解析

    Spring 系列教程之自定义标签的解析 在之前的章节中,我们提到了在 Spring 中存在默认标签与自定义标签两种,而在上一章节中我们分析了 Spring 中对默认标签的解析过程,相信大家一定已经有 ...

  5. 服装类Web原型制作分享——Rodd & Gunn

    Rodd & Gunn是国外知名的服装类品牌,服装种类繁多,有衣服.帽子.穿戴饰品等. 本原型由国产Mockplus(原型工具)和iDoc(智能标注,一键切图工具)提供. 网站原型以图文排版为 ...

  6. Vue单页面应用

    单页面应用指一个系统只加载一次资源,然后下面的操作交互.数据交互是通过router.ajax来进       行,页面并没有刷新:<1>在vue搭建的环境里面怎么有没有公用的css和js? ...

  7. 自定义注解与validation结合使用案例

    编写validation自定义注解: @Target({ ElementType.FIELD, ElementType.METHOD })@Retention(RetentionPolicy.RUNT ...

  8. Alpha 冲刺 (2/10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前端界面的开发 搭建测试用服务器的环境 完成 ...

  9. 2019.01.20 bzoj2238: Mst(kruskal+树链剖分)

    传送门 树链剖分菜题. 题意简述:给一个无向图,边有边权,每次询问删一条边(对后面的询问无影响)之后的最小生成树. 思路: 先跑一次kruskalkruskalkruskal并把跑出来的最小生成树给链 ...

  10. 2018.12.17 bzoj1406 : [AHOI2007]密码箱(简单数论)

    传送门 简单数论暴力题. 题目简述:要求求出所有满足x2≡1mod&ThinSpace;&ThinSpace;nx^2\equiv1 \mod nx2≡1modn且0≤x<n0\ ...