Web 中批量 OData 请求的 NULL HttpContext API - 错误的设计模式?
NULL HttpContext for batched OData requests in Web API - wrong design pattern?
我正在尝试确定将依赖项注入控制器的正确方法,其中要注入的具体类型是基于路由数据参数的变量。
到目前为止,我已经完成了以下设置,非常适合正常请求:
控制器
public class OrdersController : ODataController
{
private IOrderService ErpService { get; }
public OrdersController(IOrderService orderService)
{
ErpService = orderService;
}
[EnableQuery(PageSize = 100)]
public IQueryable<OrderDto> Get(ODataQueryOptions<OrderDto> queryOptions)
{
return ErpService.Orders(queryOptions);
}
...
// Post
// Patch/Put
// Delete
}
使用以下 OData 路由配置,我可以指定路由模板应包含一个 'company' 参数:
配置
config.MapODataServiceRoute( "ODataRoute", "data/{company}", model, new DefaultODataPathHandler(),
conventions, new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
这使我可以使用静态方法从 URL:
中读取公司 ID
public static string GetSalesCompanyFromRequest()
{
var salesCompany = "";
if (HttpContext.Current == null) return "";
var routeData = HttpContext.Current.Request.RequestContext.RouteData;
if (routeData.Values.ContainsKey("company"))
{
salesCompany = routeData.Values["company"].ToString();
}
return salesCompany;
}
然后,使用 Ninject,我可以选择要使用的 IOrderService 的具体实例(为简洁起见进行了简化):
kernel.Bind<IOrderService>()
.To<SageOrderService>()
.When(ctx => GetSalesCompanyFromRequest() == "101").InRequestScope();
kernel.Bind<IOrderService>()
.To<DynamicsAxOrderService>()
.When(ctx => GetSalesCompanyFromRequest() == "222").InRequestScope();
kernel.Bind<IOrderService>()
.To<SapOrderService>()
.When(ctx => GetSalesCompanyFromRequest() == "333").InRequestScope();
连接器配置
Id ErpType ConnectionString
--------------------------------------------
111 Sage "connectionstring1"
222 DynamicsAx "connectionstring2"
333 SAP "connectionstring3"
下面是 URL 的处理方式:
http://odata-demo/data/101/Orders
创建 SageOrderService
并将其注入 OrdersController
http://odata-demo/data/222/订单数
创建 DynamicsAxOrderService
并将其注入 OrdersController
同样的逻辑适用于许多不同的服务,例如:
- SageStockService/AxStockService
- SageBomService/AxBomService
- 等等
注:
我选择将公司 ID 放在 URL 中,这样我就可以配置反向代理,将请求转发到更靠近目标数据库的本地 Web 服务器。
在我尝试使用 OData Batching 之前,这一切都完美无缺。
当我发送批处理请求时,似乎没有 HttpContext.Current
(它是空的)。
This question 询问类似的问题但不考虑 OData 批处理请求。
Comments 在这个答案中建议通过路由数据注入是代码味道但没有详细说明。
所以,问题是,如何为批处理的 OData 请求获取 HttpContext.Current
?或者有没有更好的方法来做我想做的事情?
由于公司已经在路由数据中,我可以向每个单独的操作添加一个额外的公司参数,如下所示,以允许传入公司编号,然后使用工厂获取正确的具体类型:
public class OrdersController : ODataController
{
[EnableQuery(PageSize = 100)]
public IQueryable<OrderDto> Get(ODataQueryOptions<OrderDto> queryOptions, string company)
{
var erpService = ErpServiceFactory.GetService(company);
return erpService.Orders(queryOptions);
}
...
// Post
// Patch/Put
// Delete
}
这意味着我还必须在每个有点异味的操作中初始化 OrderService。
我想如果我使用 ActionFilter 来定位并将正确的具体类型传递给操作,这可能不会那么臭:
public class RequiresOrderServiceAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
string salesCompany = "";
var data = actionContext.Request.GetRouteData();
if (data.Values.ContainsKey("company"))
{
salesCompany = data.Values["company"].ToString();
var orderService = ErpServiceFactory.GetService(company);
actionContext.ActionArguments.Add("erpService", orderService);
}
}
}
public class OrdersController : ODataController
{
[EnableQuery(PageSize = 100)]
public IQueryable<OrderDto> Get(ODataQueryOptions<OrderDto> queryOptions, IOrderService erpService)
{
return erpService.Orders(queryOptions);
}
...
// Post
// Patch/Put
// Delete
}
想法?
我正在尝试确定将依赖项注入控制器的正确方法,其中要注入的具体类型是基于路由数据参数的变量。
到目前为止,我已经完成了以下设置,非常适合正常请求:
控制器
public class OrdersController : ODataController
{
private IOrderService ErpService { get; }
public OrdersController(IOrderService orderService)
{
ErpService = orderService;
}
[EnableQuery(PageSize = 100)]
public IQueryable<OrderDto> Get(ODataQueryOptions<OrderDto> queryOptions)
{
return ErpService.Orders(queryOptions);
}
...
// Post
// Patch/Put
// Delete
}
使用以下 OData 路由配置,我可以指定路由模板应包含一个 'company' 参数:
配置
config.MapODataServiceRoute( "ODataRoute", "data/{company}", model, new DefaultODataPathHandler(),
conventions, new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
这使我可以使用静态方法从 URL:
中读取公司 IDpublic static string GetSalesCompanyFromRequest()
{
var salesCompany = "";
if (HttpContext.Current == null) return "";
var routeData = HttpContext.Current.Request.RequestContext.RouteData;
if (routeData.Values.ContainsKey("company"))
{
salesCompany = routeData.Values["company"].ToString();
}
return salesCompany;
}
然后,使用 Ninject,我可以选择要使用的 IOrderService 的具体实例(为简洁起见进行了简化):
kernel.Bind<IOrderService>()
.To<SageOrderService>()
.When(ctx => GetSalesCompanyFromRequest() == "101").InRequestScope();
kernel.Bind<IOrderService>()
.To<DynamicsAxOrderService>()
.When(ctx => GetSalesCompanyFromRequest() == "222").InRequestScope();
kernel.Bind<IOrderService>()
.To<SapOrderService>()
.When(ctx => GetSalesCompanyFromRequest() == "333").InRequestScope();
连接器配置
Id ErpType ConnectionString
--------------------------------------------
111 Sage "connectionstring1"
222 DynamicsAx "connectionstring2"
333 SAP "connectionstring3"
下面是 URL 的处理方式:
http://odata-demo/data/101/Orders
创建 SageOrderService
并将其注入 OrdersController
http://odata-demo/data/222/订单数
创建 DynamicsAxOrderService
并将其注入 OrdersController
同样的逻辑适用于许多不同的服务,例如:
- SageStockService/AxStockService
- SageBomService/AxBomService
- 等等
注: 我选择将公司 ID 放在 URL 中,这样我就可以配置反向代理,将请求转发到更靠近目标数据库的本地 Web 服务器。
在我尝试使用 OData Batching 之前,这一切都完美无缺。
当我发送批处理请求时,似乎没有 HttpContext.Current
(它是空的)。
This question 询问类似的问题但不考虑 OData 批处理请求。
Comments 在这个答案中建议通过路由数据注入是代码味道但没有详细说明。
所以,问题是,如何为批处理的 OData 请求获取 HttpContext.Current
?或者有没有更好的方法来做我想做的事情?
由于公司已经在路由数据中,我可以向每个单独的操作添加一个额外的公司参数,如下所示,以允许传入公司编号,然后使用工厂获取正确的具体类型:
public class OrdersController : ODataController
{
[EnableQuery(PageSize = 100)]
public IQueryable<OrderDto> Get(ODataQueryOptions<OrderDto> queryOptions, string company)
{
var erpService = ErpServiceFactory.GetService(company);
return erpService.Orders(queryOptions);
}
...
// Post
// Patch/Put
// Delete
}
这意味着我还必须在每个有点异味的操作中初始化 OrderService。
我想如果我使用 ActionFilter 来定位并将正确的具体类型传递给操作,这可能不会那么臭:
public class RequiresOrderServiceAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
string salesCompany = "";
var data = actionContext.Request.GetRouteData();
if (data.Values.ContainsKey("company"))
{
salesCompany = data.Values["company"].ToString();
var orderService = ErpServiceFactory.GetService(company);
actionContext.ActionArguments.Add("erpService", orderService);
}
}
}
public class OrdersController : ODataController
{
[EnableQuery(PageSize = 100)]
public IQueryable<OrderDto> Get(ODataQueryOptions<OrderDto> queryOptions, IOrderService erpService)
{
return erpService.Orders(queryOptions);
}
...
// Post
// Patch/Put
// Delete
}
想法?