返回 T 列表的 Blazor 通用 API

问题描述 投票:0回答:2

我正在构建一些 blazor 应用程序 并希望有一些可以从共享项目返回任何类型的通用方法。

这个想法是我想做的:

 List<GSPparam> parameters.... // stored proc params
 List<person> ret = await this._ihttp.Post<List<person>>("api/...",parameters )

在 API 中:

 [HttpPost]
 [Route("...")]
 public async Task<T> ExecProcTable<T>( [FromBody] List<GSPparam> parameters)
{  
 ....
 somehow KNOWN WHAT THE T IS ?
 in this case List<person>
 so
 List<person> ret = ..... ;
 return ok (ret)
}

但我不知道如何从共享项目传递此类型。 通过字符串?和一些反思? 请指教。

c# .net generics blazor
2个回答
0
投票

这并不容易,因为 json 没有

T
的概念。

要么使用各种评论中建议的系统之一,要么编写自己的代码。

我的方法是创建一个基本控制器。这是一个 CQS 数据管道,而不是好的旧存储库模式,但它演示了概念:

[ApiController]
public abstract class AppControllerBase<TRecord>
    : ControllerBase
    where TRecord : class, new()
{
    protected ICQSDataBroker _dataBroker;

    public AppControllerBase(ICQSDataBroker dataBroker)
        => _dataBroker = dataBroker;

    [Mvc.Route("/api/[controller]/listquery")]
    [Mvc.HttpPost]
    public async Task<ListProviderResult<TRecord>> ListQuery([FromBody] ListQuery<TRecord> query)
        => await _dataBroker.ExecuteAsync<TRecord>(query);

    [Mvc.Route("/api/[controller]/addrecordcommand")]
    [Mvc.HttpPost]
    public async Task<CommandResult> AddRecordCommand([FromBody] AddRecordCommand<TRecord> command)
        => await _dataBroker.ExecuteAsync<TRecord>(command);
/....
}

然后像这样实现真正的控制器:

[ApiController]
public class DboWeatherForecastController : AppControllerBase<DboWeatherForecast>
{
    public DboWeatherForecastController(ICQSDataBroker dataBroker)
        : base(dataBroker)
    { }
}

调用的 API 数据代理端如下所示:


    public async ValueTask<ListProviderResult<TRecord>> ExecuteAsync<TRecord>(ListQuery<TRecord> query) where TRecord : class, new()
    {
        ListProviderResult<TRecord>? result = null;

        var entityname = (new TRecord()).GetType().Name;
        var response = await _httpClient.PostAsJsonAsync<ListQuery<TRecord>>($"/api/{entityname}/listquery", query);

        if (response.IsSuccessStatusCode)
            result = await response.Content.ReadFromJsonAsync<ListProviderResult<TRecord>>();

        return result ?? new ListProviderResult<TRecord>();
    }

    public async ValueTask<CommandResult> ExecuteAsync<TRecord>(AddRecordCommand<TRecord> command) where TRecord : class, new()
    {
        CommandResult? result = null;

        var entityname = (new TRecord()).GetType().Name;
        var response = await _httpClient.PostAsJsonAsync<AddRecordCommand<TRecord>>($"/api/{entityname}/addrecordcommand", command);

        if (response.IsSuccessStatusCode)
            result = await response.Content.ReadFromJsonAsync<CommandResult>();

        return result ?? new CommandResult();
    }

在客户端,我有一个 API DataBroker,其方法如下所示:

    public async ValueTask<ListProviderResult<TRecord>> ExecuteAsync<TRecord>(ListQuery<TRecord> query) where TRecord : class, new()
    {
        ListProviderResult<TRecord>? result = null;

        var entityname = (new TRecord()).GetType().Name;
        this.SetHTTPClientSecurityHeader();
        var response = await _httpClient.PostAsJsonAsync<ListQuery<TRecord>>($"/api/{entityname}/listquery", query);

        if (response.IsSuccessStatusCode)
            result = await response.Content.ReadFromJsonAsync<ListProviderResult<TRecord>>();

        return result ?? new ListProviderResult<TRecord>();
    }

    public async ValueTask<CommandResult> ExecuteAsync<TRecord>(AddRecordCommand<TRecord> command) where TRecord : class, new()
    {
        CommandResult? result = null;

        var entityname = (new TRecord()).GetType().Name;
        this.SetHTTPClientSecurityHeader();
        var response = await _httpClient.PostAsJsonAsync<AddRecordCommand<TRecord>>($"/api/{entityname}/addrecordcommand", command);

        if (response.IsSuccessStatusCode)
            result = await response.Content.ReadFromJsonAsync<CommandResult>();

        return result ?? new CommandResult();
    }

    protected virtual void SetHTTPClientSecurityHeader()
    {
        // add your security headers
    }

(为了简单起见,我没有包含所有安全性、异常处理和不良响应内容)。


-1
投票

我将仅使用反射来回答我在其他一些 stackoverflow 主题的帮助下得出的解决方案;)

使用反射将泛型方法执行到字符串传递的类型列表中

我正在做这样的事

_ihttp.Post<IEnumerable<T>>("api/GSP/ExecProc/List/" + ProcedureName + "/"+ typeof(T).Name+ "/" + CommandTimeout.ToString(), _parameters, CommandTimeout + 5, cts);

因此将此 T 类型作为字符串发送到 url 中

以及 API 控制器中

private static async Task<IEnumerable> AwaitQueryAsyncResult<T>(Task<IEnumerable<T>> task)
 => await task;


[HttpPost]
[Route("ExecProc/List/{SPname}/{TypeName}/{Timeout:int=30}")]
public async Task<IActionResult> ExecProcList(string SPname,string TypeName, int timeout , [FromBody] List<GSPparam> parameters)
{

 Type type = type = Type.GetType("XXX.Shared.Classes." + TypeName + ", XXX.Shared")!;

if (type is null) throw new ArgumentException(string.Format("type {0} not found", TypeName));


   IEnumerable l = (IEnumerable)Activator.CreateInstance(typeof(List<>).MakeGenericType(type))!;

      
   System.Reflection.MethodInfo method = _sql.GetType().GetMethods().Where(c => c.Name == ("QueryAsync") && c.GetParameters()[1].ParameterType == typeof(List<GSPparam>)).First().MakeGenericMethod(new Type[] { type });
       
object[] args = { SPname, parameters, CommandType.StoredProcedure, timeout, "Default" };

        var task = method.Invoke(this._sql, args);

        var miAwaitQueryAsyncResult = typeof(GSPController).GetMethod(nameof(AwaitQueryAsyncResult), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)!
            .MakeGenericMethod(type);

        var resultAsEnumerable = await (Task<IEnumerable>)miAwaitQueryAsyncResult.Invoke(null, new[] { task })!;

        return Ok(resultAsEnumerable);

请让我知道您对这种解决方案有何看法。该类型必须位于共享类命名空间中,仅此而已? 最好的问候

© www.soinside.com 2019 - 2024. All rights reserved.