現在、C# Asp.Net Core アプリケーション用の OData Api を開発しています。
API の仕様に準拠するには、URL がマルチテナント アーキテクチャに従う必要があります。
https://website.com/api/tenants/{tenantId}/odata/
OData 4.0 には動的ベース URL を実装する方法が指定されていないため、次の回避策を実装しました。ミドルウェアを使用して、HTTP コンテキストの動的テナント ID を静的文字列「tenantId」に置き換えます。ここで、OData メタデータを変更/操作して、応答でこの回避策を元に戻す方法を見つける必要があります。
実装例
Starup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
private IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDependencies(Configuration);
services.AddDbContext<DBContext>();
services.AddOData();
services.AddODataQueryFilter();
services.AddAutoMapper();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Custom Workaround Middleware
app.Use(async (context, next) =>
{
// TGis Method parses the tenant id from the Request.Path, replaces it and wries it to the context.Items to maintain the information for later
(Microsoft.AspNetCore.Http.HttpContext contextwTid, System.Guid tenantGuid) = ODataHelper.ParseTenantIDToContext(context);
context = contextwTid;
await next.Invoke();
});
app.UseMvc(b =>
{
b.Select().Filter().OrderBy().MaxTop(100).Count();
b.MapODataServiceRoute(
routeName: "odata",
routePrefix: "api/tenants/tenantId/odata",
model: ODataHelper.GetEdmModel());
});
}
ODataHelper:
...
public static (Microsoft.AspNetCore.Http.HttpContext, Guid) ParseTenantIDToContext(Microsoft.AspNetCore.Http.HttpContext context)
{
System.Guid tenantGuid = System.Guid.Empty;
if (context.Request.Path.ToString().Split('/').Length > 3 && context.Request.Path.ToString().ToLower().Contains("odata"))
{
bool isValidGUID = System.Guid.TryParse(context.Request.Path.ToString().Split('/')[3], result: out tenantGuid);
if (isValidGUID)
context.Request.Path = context.Request.Path.Value.Replace(context.Request.Path.ToString().Split('/')[3], "tenantId");
context.Items["tenantId"] = tenantGuid.ToString();
}
return (context, tenantGuid);
}
...
コントローラーの例:
public class ClientsController : ODataController
{
private readonly DBService<Client> _service;
public ClientsController(DBService<Client> service)
{
_service = service;
}
[HttpGet]
[EnableQuery]
[ODataRoute("Clients")]
public async Task<IEnumerable<Client>> Get(
ODataQueryOptions<Client> options)
{
System.Guid tenantId = ODataHelper.GetTenantIDFromContext(this.HttpContext);
IQueryable res = await _service.Get(
tenantId,
AuthorizationHelper.GetSubjectId(tenantId, User),
AuthorizationHelper.GetAllowedUserRoles(RoleType.Reporting),
options,
null);
return new List<Client>(res.Cast<Client>());
}
}
質問:
- Asp.Net Core を使用して OData に動的ベース ルーティングを実装するより良い方法はありますか?
- リクエストまたは OData メタデータを操作する方法はありますか。詳細には、応答は、"@OData.context" および (今後) OData ページング メタデータに動的な tenantId を含む元の URL を表示する必要があります。
これまでの調査/グーグル:
- WebApi の ODataMediaTypeFormatter ですが、.net Core の実装が見つかりませんでした。
- WebApi 2.2 のソリューションですが、.net Core には UrlHelper がありません。
- 公式の OData WebApi チュートリアルですが、これはワークロードよりも簡単な方法を証明するものではありません。