如何在自托管Web API与Windows服务间实现对象共享?
问题描述
我已创建一个简单的自托管Web API,以及一个本质为Windows服务的服务器。服务代码如下:
protected override void OnStart(string[] args) { var config = new HttpSelfHostConfiguration("http://localhost:8085"); config.Routes.MapHttpRoute( name: "API", routeTemplate: "{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); HttpSelfHostServer server = new HttpSelfHostServer(config); server.OpenAsync().Wait(); }
Web API代码如下:
public class ValuesController : ApiController { public String GetString(Int32 id) { return "Test data"; } }
请问是否可以在该服务与Web API之间实现对象共享?例如在服务中连接数据库服务器,在Web API中使用该连接对象等。我对此毫无思路,在网上搜索也未找到合适的解决方案。
解决方案
当然可以实现服务与Web API之间的对象共享,以下是几种可行方案:
1. 使用ASP.NET Web API依赖注入(推荐)
这是最规范的实现方式,通过Web API的依赖解析器注册和共享对象:
- 在Windows服务的
OnStart方法中初始化需要共享的对象(如数据库连接工厂、EF DbContext等) - 配置Web API的依赖解析器,将对象注册为单例或对应生命周期的实例
- 在API控制器中通过构造函数注入获取对象
示例修改代码:
// 服务OnStart方法中注册依赖 protected override void OnStart(string[] args) { var config = new HttpSelfHostConfiguration("http://localhost:8085"); // 初始化共享的数据库连接工厂 var dbConnectionFactory = new DbConnectionFactory("your_connection_string"); // 配置自定义依赖解析器 config.DependencyResolver = new SimpleDependencyResolver(dbConnectionFactory); config.Routes.MapHttpRoute( name: "API", routeTemplate: "{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); HttpSelfHostServer server = new HttpSelfHostServer(config); server.OpenAsync().Wait(); } // 自定义简单依赖解析器 public class SimpleDependencyResolver : IDependencyResolver { private readonly object _sharedInstance; public SimpleDependencyResolver(object sharedInstance) { _sharedInstance = sharedInstance; } public object GetService(Type serviceType) { if (serviceType == typeof(DbConnectionFactory)) return _sharedInstance; return null; } public IEnumerable<object> GetServices(Type serviceType) { return Enumerable.Empty<object>(); } public IDependencyScope BeginScope() { return this; } public void Dispose() { // 按需释放资源 } } // 修改控制器通过构造函数注入获取对象 public class ValuesController : ApiController { private readonly DbConnectionFactory _dbFactory; public ValuesController(DbConnectionFactory dbFactory) { _dbFactory = dbFactory; } public String GetString(Int32 id) { // 使用连接工厂创建数据库连接 using(var conn = _dbFactory.CreateConnection()) { // 执行数据库操作 return "Test data from DB"; } } }
2. 使用静态类存储共享对象
如果场景简单,可通过静态类存放共享对象,但必须注意线程安全:
// 静态共享资源类 public static class SharedResources { public static DbConnectionFactory DbFactory { get; set; } // 可变状态需加锁保证线程安全 private static readonly object _lockObj = new object(); } // 服务OnStart中初始化 protected override void OnStart(string[] args) { lock(SharedResources._lockObj) { SharedResources.DbFactory = new DbConnectionFactory("your_connection_string"); } var config = new HttpSelfHostConfiguration("http://localhost:8085"); // 路由配置... HttpSelfHostServer server = new HttpSelfHostServer(config); server.OpenAsync().Wait(); } // 控制器中使用 public class ValuesController : ApiController { public String GetString(Int32 id) { using(var conn = SharedResources.DbFactory.CreateConnection()) { // 执行数据库操作 return "Test data"; } } }
注意:不推荐直接共享数据库连接对象,数据库连接应随用随建、用完即释放(通过
using语句),共享连接工厂或DbContext更合理,可利用ADO.NET连接池管理连接。
3. 服务定位器模式
通过全局服务容器获取共享对象,属于依赖注入的变体,适合快速改造现有代码:
// 全局服务容器 public static class ServiceLocator { private static readonly Dictionary<Type, object> _services = new Dictionary<Type, object>(); private static readonly object _lockObj = new object(); public static void Register<T>(T instance) { lock(_lockObj) { _services[typeof(T)] = instance; } } public static T Get<T>() { lock(_lockObj) { if(_services.TryGetValue(typeof(T), out var instance)) return (T)instance; throw new InvalidOperationException($"未注册类型为{typeof(T)}的服务"); } } } // 服务OnStart中注册对象 protected override void OnStart(string[] args) { ServiceLocator.Register(new DbConnectionFactory("your_connection_string")); // 其他配置... } // 控制器中获取对象 public class ValuesController : ApiController { public String GetString(Int32 id) { var dbFactory = ServiceLocator.Get<DbConnectionFactory>(); using(var conn = dbFactory.CreateConnection()) { // 执行数据库操作 return "Test data"; } } }
关键注意事项
- 避免直接共享数据库连接:数据库连接是有状态资源,应由连接池管理,推荐共享连接工厂或DbContext
- 保证线程安全:若共享对象是可变状态,必须通过锁或线程安全结构确保多线程环境下的稳定性
- 合理管理生命周期:根据对象特性选择单例、作用域等生命周期,避免内存泄漏
内容的提问来源于stack exchange,提问作者Usama Alam
相关产品推荐
相关产品推荐

