使用 Microsoft.HttpClient 和 HttpContentExtensions 的通用 POST 请求

发布于 2024-10-13 05:05:50 字数 2658 浏览 7 评论 0原文

我正在使用 WCF REST Starter Kit 中提供的极其出色的 HttpClient。我有以下针对 HelloTxt API 的方法:

public UserValidateResponse Validate()
{
    HttpClient client = new HttpClient(baseUrl);

    HttpMultipartMimeForm form = new HttpMultipartMimeForm();
    form.Add("app_key", this.AppKey);
    form.Add("user_key", this.UserKey);
    HttpResponseMessage response = client.Post("user.validate", form.CreateHttpContent());

    return response.Content.ReadAsXmlSerializable<UserValidateResponse>();
}

我有一个很好的通用 GetRequest 方法,如下所示:

public T GetRequest<T>(string query)
{
    HttpClient client = new HttpClient(baseUrl);
    client.DefaultHeaders.UserAgent.AddString(@"http://www.simply-watches.co.uk/");

    HttpResponseMessage response = client.Get(query);
    response.EnsureStatusIsSuccessful();

    T data = default(T);
    try
    {
        data = response.Content.ReadAsXmlSerializable<T>();
        return data;
    }
    catch (Exception ex)
    {
        Console.Write(String.Format("{0}: {1}", ex.Message, ex.InnerException.Message));
    }

    return data;
}

其好处是您可以根据此随机示例将其 T 作为响应类型传递:

public List<User> GetUsers(int deptid)
{
    string query = String.Format("department.getUsers?api_key={0}&dept_id={1}", this.APIKey, deptId);

    return GetRequest<List<User>>(query);
}

我现在想要相同的通用风格 POST 方法,而不是 GET,我确信我可以使用 HttpContentExtensions,但我不知道如何将请求转换为 HttpMultipartMimeForm。这是我到目前为止所拥有的:

public T PostRequest<K, T>(string query, K request)
{
    HttpClient client = new HttpClient(baseUrl);
    // the following line doesn't work! Any suggestions?
    HttpContent content = HttpContentExtensions.CreateDataContract<K>(request, Encoding.UTF8, "application/x-www-form-urlencoded", typeof(HttpMultipartMimeForm));

    HttpResponseMessage response = client.Post(query, content);
    response.EnsureStatusIsSuccessful();

    T data = default(T);
    try
    {
        data = response.Content.ReadAsXmlSerializable<T>();
        return data;
    }
    catch (Exception ex)
    {
        Console.Write(String.Format("{0}: {1}", ex.Message, ex.InnerException.Message));
    }

    return data;
}

它将被这样调用:

UserValidateResponse response = PostRequest<UserValidateRequest, UserValidateResponse>("user.validate", new UserValidateRequest(this.AppKey, this.UserKey));

它是针对此 API 工作的: http:// hellotxt.com/developers/documentation。非常欢迎任何建议!我可以为每个 POST 定义不同的表单,但最好通用地执行此操作。

I am using the extremely awesome HttpClient provided in the WCF REST Starter Kit. I have the following method that is working against the HelloTxt API:

public UserValidateResponse Validate()
{
    HttpClient client = new HttpClient(baseUrl);

    HttpMultipartMimeForm form = new HttpMultipartMimeForm();
    form.Add("app_key", this.AppKey);
    form.Add("user_key", this.UserKey);
    HttpResponseMessage response = client.Post("user.validate", form.CreateHttpContent());

    return response.Content.ReadAsXmlSerializable<UserValidateResponse>();
}

I have a nice generic GetRequest method that looks like this:

public T GetRequest<T>(string query)
{
    HttpClient client = new HttpClient(baseUrl);
    client.DefaultHeaders.UserAgent.AddString(@"http://www.simply-watches.co.uk/");

    HttpResponseMessage response = client.Get(query);
    response.EnsureStatusIsSuccessful();

    T data = default(T);
    try
    {
        data = response.Content.ReadAsXmlSerializable<T>();
        return data;
    }
    catch (Exception ex)
    {
        Console.Write(String.Format("{0}: {1}", ex.Message, ex.InnerException.Message));
    }

    return data;
}

The benefit of which is that you can pass it T as the response type as per this random example:

public List<User> GetUsers(int deptid)
{
    string query = String.Format("department.getUsers?api_key={0}&dept_id={1}", this.APIKey, deptId);

    return GetRequest<List<User>>(query);
}

I now want to the same generic style POST method, rather than GET and I'm sure I can use the HttpContentExtensions, but I can't figure out how to transform the request into a HttpMultipartMimeForm. this is what I have so far:

public T PostRequest<K, T>(string query, K request)
{
    HttpClient client = new HttpClient(baseUrl);
    // the following line doesn't work! Any suggestions?
    HttpContent content = HttpContentExtensions.CreateDataContract<K>(request, Encoding.UTF8, "application/x-www-form-urlencoded", typeof(HttpMultipartMimeForm));

    HttpResponseMessage response = client.Post(query, content);
    response.EnsureStatusIsSuccessful();

    T data = default(T);
    try
    {
        data = response.Content.ReadAsXmlSerializable<T>();
        return data;
    }
    catch (Exception ex)
    {
        Console.Write(String.Format("{0}: {1}", ex.Message, ex.InnerException.Message));
    }

    return data;
}

It would be called like this:

UserValidateResponse response = PostRequest<UserValidateRequest, UserValidateResponse>("user.validate", new UserValidateRequest(this.AppKey, this.UserKey));

It is to work against this API: http://hellotxt.com/developers/documentation. Any suggestions are extremely welcome! I could define a different form for each POST, but it would be nice to do this generically.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独守阴晴ぅ圆缺 2024-10-20 05:05:50

我对此回答了我自己的问题。该代码可以在我的 HelloTxt API 的 .NET 包装器中看到 - HelloTxt.NET,根据我上面的评论,使用反射来计算请求对象属性,并使用值填充 HttpMultipartMimeForm(),同时检查 Required< /code> 类属性上的数据注释。

有问题的代码是:

/// <summary>
/// Generic post request.
/// </summary>
/// <typeparam name="K">Request Type</typeparam>
/// <typeparam name="T">Response Type</typeparam>
/// <param name="query">e.g. user.validate</param>
/// <param name="request">The Request</param>
/// <returns></returns>
public T PostRequest<K, T>(string query, K request)
{
    using (var client = GetDefaultClient())
    {
        // build form data post
        HttpMultipartMimeForm form = CreateMimeForm<K>(request);

        // call method
        using (HttpResponseMessage response = client.Post(query, form.CreateHttpContent()))
        {
            response.EnsureStatusIsSuccessful();
            return response.Content.ReadAsXmlSerializable<T>();
        }
    }
}

/// <summary>
/// Builds a HttpMultipartMimeForm from a request object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns></returns>
public HttpMultipartMimeForm CreateMimeForm<T>(T request)
{
    HttpMultipartMimeForm form = new HttpMultipartMimeForm();

    Type type = request.GetType();
    PropertyInfo[] properties = type.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        foreach (Attribute attribute in property.GetCustomAttributes(true))
        {
            RequiredAttribute requiredAttribute = attribute as RequiredAttribute;
            if (requiredAttribute != null)
            {
                if (!requiredAttribute.IsValid(property.GetValue(request, null)))
                {
                    //Console.WriteLine("{0} [type = {1}] [value = {2}]", property.Name, property.PropertyType, property.GetValue(property, null));
                    throw new ValidationException(String.Format("{0} [type = {1}] requires a valid value", property.Name, property.PropertyType));
                }
            }
        }

        if (property.PropertyType == typeof(FileInfo))
        {
            FileInfo fi = (FileInfo)property.GetValue(request, null);
            HttpFormFile file = new HttpFormFile();
            file.Content = HttpContent.Create(fi, "application/octet-stream");
            file.FileName = fi.Name;
            file.Name = "image";

            form.Files.Add(file);
        }
        else
        {
            form.Add(property.Name, String.Format("{0}", property.GetValue(request, null)));
        }
    }

    return form;
}

I answered my own question on this. The code can be seen in my .NET wrapper for the HelloTxt API - HelloTxt.NET, and as per my comment above, uses reflection to work out the request object properties, and populates a HttpMultipartMimeForm() with the values, whilst checking the Required data annotions on the class properties.

The code in question is:

/// <summary>
/// Generic post request.
/// </summary>
/// <typeparam name="K">Request Type</typeparam>
/// <typeparam name="T">Response Type</typeparam>
/// <param name="query">e.g. user.validate</param>
/// <param name="request">The Request</param>
/// <returns></returns>
public T PostRequest<K, T>(string query, K request)
{
    using (var client = GetDefaultClient())
    {
        // build form data post
        HttpMultipartMimeForm form = CreateMimeForm<K>(request);

        // call method
        using (HttpResponseMessage response = client.Post(query, form.CreateHttpContent()))
        {
            response.EnsureStatusIsSuccessful();
            return response.Content.ReadAsXmlSerializable<T>();
        }
    }
}

/// <summary>
/// Builds a HttpMultipartMimeForm from a request object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns></returns>
public HttpMultipartMimeForm CreateMimeForm<T>(T request)
{
    HttpMultipartMimeForm form = new HttpMultipartMimeForm();

    Type type = request.GetType();
    PropertyInfo[] properties = type.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        foreach (Attribute attribute in property.GetCustomAttributes(true))
        {
            RequiredAttribute requiredAttribute = attribute as RequiredAttribute;
            if (requiredAttribute != null)
            {
                if (!requiredAttribute.IsValid(property.GetValue(request, null)))
                {
                    //Console.WriteLine("{0} [type = {1}] [value = {2}]", property.Name, property.PropertyType, property.GetValue(property, null));
                    throw new ValidationException(String.Format("{0} [type = {1}] requires a valid value", property.Name, property.PropertyType));
                }
            }
        }

        if (property.PropertyType == typeof(FileInfo))
        {
            FileInfo fi = (FileInfo)property.GetValue(request, null);
            HttpFormFile file = new HttpFormFile();
            file.Content = HttpContent.Create(fi, "application/octet-stream");
            file.FileName = fi.Name;
            file.Name = "image";

            form.Files.Add(file);
        }
        else
        {
            form.Add(property.Name, String.Format("{0}", property.GetValue(request, null)));
        }
    }

    return form;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文