通用的GET Web API端点,用于System.Type和Id。

huangapple go评论67阅读模式
英文:

Generic GET web api endpoint for System.Type and Id

问题

我正在使用 net 7 中的 Web API。有没有办法使绑定引擎理解 Typeobject id 参数?

我有一个希望重用的端点,通过 id 获取特定类型的实体。

据我所知,在操作中不支持泛型类型,所以我猜我需要类似这样的东西:

[HttpGet("{id}")]
public object Get(Type type, object id) 
{
    // 调用 _entityFrameWorkDatabaseContext.Find(Type type, object id)
}

我想使用类似 /theAction/1?type=<AssemblyQualifiedName> 这样的方式调用它。这可能吗?

英文:

I'm using web api in net 7. Is there any way to make the binding engine understand a Type and an object id parameter?

I have an endpoint that I want to reuse to get an entity of a certain type by id.

AFAIK generic types are not supported in an action, so I guess what I need is something like this:

[HttpGet(&quot;{id}&quot;)]
public object Get(Type type, object id) 
{
    // call _entityFrameWorkDatabaseContext.Find(Type type, object id)
}

I would like to invoke it using something like /theAction/1?type=&lt;AssemblyQualifiedName&gt;. Is it possible?

答案1

得分: 1

自定义模型绑定器应该能够获取您所需的内容。

public class TypeEntityBinder : IModelBinder
{

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        var modelName = bindingContext.ModelName;

        // 尝试按名称获取参数的值
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var value = valueProviderResult.FirstValue;

        // 检查参数值是否为 null 或空
        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        // 将其视为字符串请求参数
        if (!string.TryParse(value, out var type))
        {
            bindingContext.ModelState.TryAddModelError(
                modelName, "Type must be a string.");

            return Task.CompletedTask;
        }

        // 在调试会话中,确保 `type` 绑定正确

        // 确保程序集名称正确并匹配真实类型
        var model = Type.GetType($"namespace.{type}, assemblyName");
        // 将结果绑定到 Type
        bindingContext.Result = ModelBindingResult.Success(model);
        return Task.CompletedTask;  // <-- 躲进山里去吧!
    }
}

然后,只需添加属性以激活自定义绑定器。

Get([ModelBinder(BinderType = typeof(TypeEntityBinder))] Type type, object id) 

请记住,这主要是理论代码。您可能会遇到的一个问题是自定义绑定器未能正确注册到请求管道中,因此请确保它实际上已经包含在内。还要通过调试技术检查 type 变量的内容。

https://learn.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-7.0

英文:

A custom model binder should be able to get you what you need.

public class TypeEntityBinder : IModelBinder
{

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        var modelName = bindingContext.ModelName;

        // Try to fetch the value of the argument by name
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var value = valueProviderResult.FirstValue;

        // Check if the argument value is null or empty
        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        // Treat it like a string request parameter
        if (!string.TryParse(value, out var type))
        {
            bindingContext.ModelState.TryAddModelError(
                modelName, &quot;Type must be a string.&quot;);

            return Task.CompletedTask;
        }

        // In a debugging session, make sure the `type` is binding correctly

        // Make sure the assembly name is correct and matches a real type
        var model = Type.GetType($&quot;namespace.{type}, assemblyName&quot;);
        // Bind the result to Type
        bindingContext.Result = ModelBindingResult.Success(model);
        return Task.CompletedTask;  // &lt;-- run for the hills!
    }
}

Then, simply slap the attribute to active the custom binder.

Get([ModelBinder(BinderType = typeof(TypeEntityBinder))] Type type, object id) 

Keep in mind, this is mostly theoretical code. One snag you could run into is the custom binder does not register properly in the request pipeline, so make sure it is actually included. Also, check the contents of the type variable via debugging techniques.

https://learn.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-7.0

答案2

得分: 0

通过将类型作为字符串获取并使用反射获取对象类型,可以实现此目的。有关反射的更多信息,请参阅[此处](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/reflection-and-attributes/#reflection-overview)。

英文:

you can do this by getting the type as a string and using reflection to get the object Type, you can read more about reflections here.

    [HttpGet(&quot;{id}&quot;)]
    public object Get(string type, int id) 
    {
        var type = Type.GetType($&quot;namespace.{type}, assemblyName&quot;);
    
        // you can add a validator here to make sure that type is valid.
        if(type == null)
        {
            // your code goes here
        }

        // here you retrieve the data from DB using ef.
        var entity = _entityFrameWorkDatabaseContext.Find(type, id);
        
        // you can check if the entity is null and do what you want
        if(entity == null)
        {
            // your code goes here
        }

       return entity;
    }
  1. try get the entity using reflections.
  2. if getting the entity type succeded call your _entityFrameWorkDatabaseContext with type and Id (int/string/etc..)
  3. return the entity.

you can call the endpoint in the following way

GET &lt;address&gt;/{id}?type=&lt;your-type&gt;

huangapple
  • 本文由 发表于 2023年3月31日 23:22:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75900205.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定