【问题标题】:Mapping the external api request based on a pattern from a general request根据来自一般请求的模式映射外部 api 请求
【发布时间】:2021-09-29 11:52:22
【问题描述】:

我有一个带有一般搜索请求的应用程序,它有一个标识号,可以是产品号或客户号之类的任何东西,以及其他搜索条件。我想显示所有结果。我正在编写一个中间件来调用搜索 api 端点。

public class GeneralRequest
    {
        public string IdentificationNumber { get; set; }
        public string Location { get; set; }
        public bool IsActive { get; set; }
        public DateTime CreatedDate { get; set; }
        public DateTime Start { get; set; }
        public DateTime Stop { get; set; }
    }

public class AdditionalSearch
    {
        public RangeSearch Range { get; set; }
        public string Location { get; set; }
        public bool IsActive { get; set; }      
    }

  public class RangeSearch
    {
        public DateTime Start { get; set; }
        public DateTime Stop { get; set; }
    }

public class GetProductRequest : AdditionalSearch, ISearchRequest
    {
        public string ProductId { get; set; }
    }

public class GetCustomerRequst : AdditionalSearch, ISearchRequest
    {
        public string CustomerNumber { get; set; }
    }

public class GetManufacturerRequest : AdditionalSearch, ISearchRequest
    {
        public string ManufacturerNumber { get; set; }
    }
// this is a dummy interface to make all the requests general
public interface ISearchRequest
    {
    }

这是我根据标识号模式创建正确请求的搜索处理器。但是我未能将 AdditonalSearch 分配给调用 func 后收到的请求。当然,它是一个没有任何内容的界面。我怎样才能通过不重复来实现这一点(我的意思是我不想重复字典中的初始化逻辑) 请建议我这里的最佳做法是什么。

public class SearchProcessor
    {
        private readonly Dictionary<Regex, Func<GeneralRequest, ISearchRequest>> _pattern;
        private readonly IAppClient _appClient;

        public SearchProcessor(IAppClient appClient)
        {
            _appClient = appClient;
            _pattern = new Dictionary<Regex, Func<GeneralRequest, ISearchRequest>>
            {
                {new Regex("/\b([0-9]|10)\b /"), p=> new GetProductRequest(){ProductId = p.IdentificationNumber} },
                {new Regex("^\\d{}1,9}$"), p=> new GetCustomerRequst(){CustomerNumber = p.IdentificationNumber} },
                {new Regex("^\\d{}1,11}$"), p=> new GetManufacturerRequest(){ManufacturerNumber = p.IdentificationNumber} }
            };
            
        }

        public List<SearchResult> GetAllSearchResults(GeneralRequest request)
        {

            var requests = _pattern.Where(r => r.Key.IsMatch(request.IdentificationNumber)).Select(v => v.Value);

            var responses = new List<SearchResult>();
            foreach (var req in requests)
            {
                var appRequest = req.Invoke(request);
                
                appRequest.AdditionalSearch = new AdditionalSearch // this is where I am not able to assign the additional seach from the general request
                {
                    Range = new RangeSearch { Start = request.Start, Stop = request.Stop}
                    IsActive = request.IsActive,
                    Location = request.Location
                };
              //This calls another api to get the response.
                responses.Add(_appclient.FindResult(appRequest));
            }
            return responses;
        }
    }

---更新-- 这里是调用外部api的appclient..

getproduct 路由的示例请求是

public class AppClient : IAppClient
{

    private readonly string _baseurl;

    private readonly string _getProductRoute;
    private readonly string _getCustomerRoute;
    private readonly string _getManufacturerRoute;

    public AppClient()
    {
        _getProductRoute = $"{_baseurl}/api/get-product";
        _getCustomerRoute = $"{_baseurl}/api/get-customer";
        _getManufacturerRoute = $"{_baseurl}/api/get-Manufacturer";
    }
    public SearchResult FindResult(ISearchRequest searchRequest)
    {
        var routes = new Dictionary<Type, string>
        {
            {typeof(GetProductRequest), _getProductRoute },
            {typeof(GetCustomerRequst), _getCustomerRoute },
            {typeof(GetManufacturerRequest), _getManufacturerRoute }
        };
        // Here it is going to be http implementation to call above routes.
        return new SearchResult();
    }
}

获取产品路径的请求是

{
   "ProductId":"",
   "RangeSearch":{
      "Start":"",
      "Stop":""
   },
   "Location":"",
   "IsActive":true
}
 

获取客户请求是

{
   "CustomerNumber":"",
   "RangeSearch":{
      "Start":"",
      "Stop":""
   },
   "Location":"",
   "IsActive":true
}

【问题讨论】:

  • 您能否提供有关 api 端点的示例,以了解中间件之外的工作方式。了解api有助于我们评估您的工作,并给予更好的帮助。
  • 感谢您的回复
  • 我更新了我的帖子,说明了 API 的调用方式。希望有意义。我删除了不必要的代码。

标签: c# api request-mapping


【解决方案1】:

您可以通过这样做来简化您的工作:

public class SearchRequest
{
    public string IdentificationNumber { get; set; }
    public string Location { get; set; }
    public bool IsActive { get; set; }
    public SearchRequestRange Range { get; set; }

    public SearchRequest(string identificationNumber)
    {
        IdentificationNumber = identificationNumber;
    }
}

public class SearchRequestRange
{
    public DateTime Start { get; set; }
    public DateTime Stop { get; set; }
}

现在不需要你正在做的过程,你只需要将你的ApiClient调整为这样的:

public class AppClient : IAppClient
{
    private static readonly IReadOnlyDictionary<string, string> _endPointsSearchPatterns = new Dictionary<string, string>
    {
        {"get-product", "/\b([0-9]|10)\b /"},
        {"get-customer", "^\\d{}1,9}$"},
        {"get-Manufacturer", "^\\d{}1,11}$"}
    };
    
    private readonly string _baseUrl;

    public AppClient(string baseUrl) 
    { 
        if(string.IsNotNullOrWhiteSpace(baseUrl))
            throw new ArgumentNullException(nameof(baseUrl));
        
        _baseurl = baseUrl;
    }
    
    public IEnumerable<SearchResult> FindResult(SearchRequest searchRequest)
    {
        var endPoints = _endPointsSearchPatterns.Where(x=> Regex.IsMatch(request.IdentificationNumber , x.Value))?.ToList();
        
        if(endPoints?.Count == 0)
        {
            yield break;
        }
            
        var responses = new List<SearchResult>();
        
        foreach(var endpoint in endPoints)
        {           
            ISearchBy search = null;

            switch(endPoint.Key)
            {
                case "get-product":
                    action = new ProductApiClient(this);
                    break;
                case "get-customer":
                    action = new ProductApiClient(this);
                    break;
                case "get-Manufacturer":
                    action = new ProductApiClient(this);                    
                    break;              
            }
            
            yield return action.SearchBy(searchRequest); 
            
        }
        
        return searchResult;
    }
}

关于 GetProductRequestGetCustomerRequstGetManufacturerRequest 这些应该被重构,相反,您可以像这样为每个实体创建一个类:

public interface ISearchBy
{
    SearchResult ISearchBy(SearchRequest request);
}

public class ProductApiClient : ISearchBy
{
    private readonly IAppClient _appClient;
    public ProductApiClient(IAppClient appClient)
    {
        _appClient = appClient; 
    }
    
    public SearchResult SearchBy(SearchRequest request)
    {
        // do stuff
    }
    
    // other related endpoints 
}


public class CustomerApiClient : ISearchBy
{
    private readonly IAppClient _appClient;
    public CustomerApiClient(IAppClient appClient)
    {
        _appClient = appClient; 
    }
    
    public SearchResult SearchBy(SearchRequest request)
    {
        // do stuff
    }
    
    // other related endpoints 
}

public class ManufacturerApiClient : ISearchBy
{
    private readonly IAppClient _appClient;
    public ManufacturerApiClient(IAppClient appClient)
    {
        _appClient = appClient; 
    }
    
    public SearchResult SearchBy(SearchRequest request)
    {
        // do stuff
    }
    
    // other related endpoints 
}

【讨论】:

  • 感谢您的建议。但是从您的解决方案来看,请求没有改变,每个端点的请求都不同。产品请求有 productId',客户请求有 Customernumber
  • @alienavatar 我已经更新了我的答案
猜你喜欢
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 2017-12-19
  • 2018-01-02
  • 2017-05-12
  • 2017-04-17
  • 2020-10-17
  • 2018-09-07
相关资源
最近更新 更多