简体   繁体   English

是否可以使用web API的通用方法?

[英]Is it ok to use generic method for web api?

I am getting data from a web api by making httpclient calls from various MVC controllers. 我通过从各种MVC控制器进行httpclient调用从web api获取数据。 Because I have to do it many times, I made a generic method that I can reuse by just passing in the api url and the model return type. 因为我必须多次这样做,所以我制作了一个通用方法,只需传入api url和模型返回类型即可重用。 It works fine, but I am concerned I am loosing the oppurtunity to have different methods, like GetPeople, GetPersonById, etc. Is there a downside to what I am doing? 它工作正常,但我担心我失去了机会,有不同的方法,如GetPeople,GetPersonById等。我正在做的事情是否有缺点?

Utilities.cs: Utilities.cs:

    public static T GetDataFromWebService<T>(T model, string svcEndPoint)
    {
        HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var response = client.GetAsync(svcEndPoint).Result;
        var result = response.Content.ReadAsAsync<T>().Result;

        return result;
    }

Controller: 控制器:

        string svc = appSettings.GetPeopleApiUrl;
        var model = new List<Person>();
        var people = Utilities.GetDataFromWebService <IEnumerable<Person>>(model, svc);

You can still have specialized methods such as GetPeople, GetPersonById by layering them on top: 您仍然可以使用专门的方法,例如GetPeople, GetPersonById ,将它们分层放在顶部:

PeopleModel GetPeople(...) {
 return GetDataFromWebService<PeopleModel>(...);
}

No downsides, it is good that you have all boilerplate code in a shared utility method. 没有缺点,您可以在共享实用程序方法中获得所有样板代码。

Well, there is definitely, better way of doing the overall implementation, but if I have to stick to the question, I would say any attempt of reducing coupling is a good step for future directions. 嗯,确实有更好的方法来进行整体实施,但如果我必须坚持这个问题,我会说任何减少耦合的尝试都是未来方向的一个很好的步骤。 In your situation, since you are abstracting away the responsibility of making service calls to a utility method, it would help you in the long run. 在您的情况下,由于您正在逐渐消除对实用程序方法进行服务调用的责任,因此从长远来看它会对您有所帮助。

Though I would suggest that instead of having this stuffed together in Utility class you should make the connectivity it's own class, something like this 虽然我建议不要将这些填充在Utility类中,而应该将连接作为自己的类,就像这样

public delegate T ParseToObject<T>(string response);

public class ServiceConnector : IServiceConnector
{
    public string LogoffUrl { get; set; }
    public bool SupportRetry { get; set; }        

    private WebClient _client;

    public ServiceConnector()
    {
    }

    public T GetResponse<T>(string requestUrl, ParseToObject<T> parsingMethod)
    {
        string response = __getResponse(requestUrl);
        return parsingMethod(response);
    }     

    private string __getResponse(string requestUrl)
    {
        string serviceResponse = string.Empty;
        try
        {
            __initializeWebClient();
            Logger.Current.LogInfo(string.Format("Sending request with URL {0}", requestUrl));
            serviceResponse = _client.DownloadString(requestUrl);
        }
        catch (Exception ex)
        {
            if (ex.Message != null) 
            {
            Logger.Current.LogException(string.Format("Exception during OvidWS request {0} ", requestUrl), ex); 
                _client = null;
            }
          //Sample implementation only, you could throw the exception up based on your domain needs
        }
        return serviceResponse;
    }

    private void __initializeWebClient()
    {
        if (_client == null)
            _client = new WebClient();
    }
}

With this in place, tomorrow, let's say you want to add support to log off, support cookies, support credentials, support retries, this is the only place where you can be and comfortably make changes. 有了这个,明天,假设您想要添加支持注销,支持cookie,支持凭据,支持重试,这是您可以轻松地进行更改的唯一地方。 Similarly if you want to use Webclient over something else, you can also do that better here. 同样,如果你想使用Webclient而不是其他东西,你也可以在这里做得更好。

Try with that helper: 试试那个助手:

 public static class WebClientExtension
{
    public static T DownloadSerializedJsonData<T>(string url) where T : new()
    {
        var contentType = ConfigurationManager.AppSettings["ContentType"];//content type in app config or web config
        using (var webClient = new WebClient())
        {
            webClient.Headers.Add("Content-Type", contentType);
            var jsonData = string.Empty;
            try
            {
                jsonData = webClient.DownloadString(url);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return !string.IsNullOrEmpty(jsonData) ? JsonConvert.DeserializeObject<T>(jsonData) : new T();
        }
    }

    public static T AuthorizationContentSerializedJsonData<T>(string url) where T : new()
    {
        string jsonData = null;
        try
        {
            var httpRequest = (HttpWebRequest)WebRequest.Create(url);
            //ClientBase.AuthorizeRequest(httpRequest, Authorization.AccessToken);
            var response = httpRequest.GetResponse();
            Stream receiveStream = response.GetResponseStream();
            var readStream = new StreamReader(receiveStream, Encoding.UTF8);
            jsonData = readStream.ReadToEnd();
            response.Close();
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return !string.IsNullOrEmpty(jsonData) ? JsonConvert.DeserializeObject<T>(jsonData) : new T();
    }
}

App confing / Web config example for content type 内容类型的App confing / Web配置示例

<add key="ContentType" value="application/hal+json; charset=UTF-8" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM