im正在构建一些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)
}
但我不知道如何从共享项目传递此类型通过字符串?和一些反思?请告知
关于
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
}
(为了简单起见,我没有包括所有的安全性、异常处理和错误响应内容(。
我将仅使用反射来回答我的解决方案,该解决方案是在其他一些stackoverflow主题的帮助下提供的;(
使用反射将泛型方法执行到字符串传递的类型列表中
我做得像
_ihttp.Post<IEnumerable<T>>("api/GSP/ExecProc/List/" + ProcedureName + "/"+ typeof(T).Name+ "/" + CommandTimeout.ToString(), _parameters, CommandTimeout + 5, cts);
因此在url 中以字符串形式发送此T类型
以及在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);
请告诉我你对这种解决方案有什么看法。类型必须在共享类命名空间中,是吗?向致以最良好的问候