我正在使用.NET的HttpClient向WebAPI发出请求,该WebAPI返回一些需要在客户端进行一些自定义反序列化的JSON数据.为此,我已经制作了自己的JsonConverter,但我无法弄清楚如何让ReadAsAsync<T>方法获得转换器的存在.
我现在通过使用ReadAsStringAsync读取响应,然后将该字符串传递给我来解决我的问题JsonConvert.DeserializeObject,但似乎应该有一个更优雅的解决方案.
这是我的代码:
public PrefsResponse GetAllPrefs(string sid) {
HttpClient client = CreateHttpClient(null, sid);
var response = client.GetAsync("api/sites/" + sid).Result;
// TODO : find a way to hook custom converters to this...
// return response.Content.ReadAsAsync<PrefsResponse>().Result;
var stringResult = response.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<PrefsResponse>(stringResult, new PrefClassJsonConverter());
}
Run Code Online (Sandbox Code Playgroud)
这是我能做的最好的,还是有更优雅的方式?
这里也是我创建HttpClient的地方,如果那是我需要连接它的地方:
private HttpClient CreateHttpClient(CommandContext ctx, string sid) {
var cookies = new CookieContainer();
var handler = new HttpClientHandler {
CookieContainer = cookies,
UseCookies = true,
UseDefaultCredentials = false …Run Code Online (Sandbox Code Playgroud) 所以我正在启动一个新的.Net 4.0项目,并将使用公共API进行一些工作.我打算使用Microsoft HttpClient类,所以我安装了最新的稳定版Microsoft.Net.Http NuGet包(版本2.2.13).我正在看一些同事放在一起的POC代码,也使用HttpClient的NuGet包,并注意到这样的代码:
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAync("/uri").Result;
DomainType result = response.Content.ReadAsAsync<DomainType>().Result;
Run Code Online (Sandbox Code Playgroud)
在我的项目中,在添加对Microsoft.Net.Http包的引用之后,当我尝试编写类似的代码时,我注意到HttpResponseMessage没有ReadAsAsync<T>()方法.在对我的同事的POC解决方案进行一些挖掘后,看起来ReadAsAsync<T>()它实际上是System.Net.Http.Formatting装配中的扩展方法.在这个POC解决方案中,有一个对System.Net.Http.Formatting的引用,但它从路径中提取此文件C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Net.Http.Formatting.dll.
我的问题是,是否有更好的解决方案来访问此扩展方法,而不是从我的本地ASP.Net安装引用此程序集?我担心这会导致我们的CI服务器出现问题,因为它不太可能安装ASP.Net.我想我可以将System.Net.Http.Formatting复制到我的解决方案中的Lib目录,但是我希望有一个更好的选择,比如我错过的另一个NuGet包会给我这个程序集.
谢谢!
我正在使用System.Net.Http的HttpClient使用以下代码使用"POST"调用REST API:
using (HttpRequestMessage requestMessage = new HttpRequestMessage(
HttpMethod.Post, new Uri(request)) { })
{
response = await httpClient.PostAsync(request, objectContent);
}
Run Code Online (Sandbox Code Playgroud)
"objectContent"目前是这个 -
objectContent = new ObjectContent(jsonContent.GetType(),
jsonContent,
new JsonMediaTypeFormatter());
Run Code Online (Sandbox Code Playgroud)
我想知道如果这是一个StringContent而不是像这样的ObjectContent会有什么不同?
objectContent = new StringContent(content);
objectContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
Run Code Online (Sandbox Code Playgroud)
两者都很好.因为它是JSON,我倾向于认为StringContent是有意义的.但是什么时候使用ObjectContent,因为几乎所有发送的内容都是"字符串".
我很难用Visual Studio 2013测试我的API控制器.我的一个解决方案有一个Web API项目和一个测试项目.在我的测试项目中,我有一个单元测试:
[TestMethod]
public void GetProduct()
{
HttpConfiguration config = new HttpConfiguration();
HttpServer _server = new HttpServer(config);
var client = new HttpClient(_server);
var request = new HttpRequestMessage
{
RequestUri = new Uri("http://localhost:50892/api/product/hello"),
Method = HttpMethod.Get
};
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var response = client.SendAsync(request).Result)
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
var test = response.Content.ReadAsAsync<CollectionListDTO>().Result;
}
}
Run Code Online (Sandbox Code Playgroud)
我一直得到404.我尝试使用一个Visual Studio实例(IIS Express)运行我的API,并尝试在另一个实例中调试此单元测试.但没有运气.我已经验证我可以将此URL放在浏览器中(当一个Visual Studio正在调试时),我看到了我的JSON响应.但我无法弄清楚如何让它与我的单元测试一起工作HttpClient.我试图在网上找到例子,但似乎找不到一个.有人可以帮忙吗?
更新1: 我尝试添加路线但没有发生任何事情.
HttpConfiguration config = new HttpConfiguration();
// Added this line
config.Routes.MapHttpRoute(name: "Default", routeTemplate: "api/product/hello/");
HttpServer _server = new …Run Code Online (Sandbox Code Playgroud) c# unit-testing asp.net-web-api dotnet-httpclient visual-studio-2013
我正在尝试在 c# .net core 中实现一个 rest 客户端,它需要首先进行基本身份验证,然后在后续请求中利用一个 Bearer 令牌。
当我尝试将基本身份验证与带有 FormUrlEncodedContent 对象的 client.PostAsync 结合使用时,出现异常:
System.InvalidOperationException occurred in System.Net.Http.dll: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
Run Code Online (Sandbox Code Playgroud)
//setup reusable http client
HttpClient client = new HttpClient();
Uri baseUri = new Uri(url);
client.BaseAddress = baseUri;
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
//Post body content
var values = new List<KeyValuePair<string,string>>();
values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
var content = new FormUrlEncodedContent(values);
//Basic Authentication
var …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
private static string boundary = "----CustomBoundary" + DateTime.Now.Ticks.ToString("x");
private static async Task<string> PostTest()
{
string servResp = "";
using (var content = new MultipartFormDataContent(boundary))
{
content.Add(new StringContent("105212"), "case-id");
content.Add(new StringContent("1/14/2014"), "dateFrom");
content.Add(new StringContent("1/15/2014"), "dateTo");
HttpClientHandler handler = new HttpClientHandler();
cookieContainer = new CookieContainer();
handler.CookieContainer = cookieContainer;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://somewebsite.com/form");
request.Headers.ExpectContinue = false;
request.Content = content;
httpClient = new HttpClient(handler);
HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
servResp = await response.Content.ReadAsStringAsync();
}
return servResp;
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我在Fiddler中看到了Content-Type标头:
Content-Type: multipart/form-data; …Run Code Online (Sandbox Code Playgroud) c# content-type multipartform-data .net-4.5 dotnet-httpclient
有没有一种方法可以Content-Type在执行GETwith 时显式设置标头值HttpClient?
我意识到这打破了1.1协议,但我正在使用一个不符合它的API,并且要求我设置一个Content-TypeHeader.
我试过这个无济于事......
using (var httpClient = new HttpClient())
{
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.com");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded+v1.3");
await httpClient.SendAsync(httpRequestMessage)
}
Run Code Online (Sandbox Code Playgroud)
我检查了DefaultRequestHeaders后TryAddWithoutValidation添加,它似乎并没有被设置的Content-Type值.
如果我尝试设置httpRequestMessage的Content-Type(通过设置httpRequestMessage.Content = ...,我收到以下错误:
Cannot send a content-body with this verb-type.
Run Code Online (Sandbox Code Playgroud)
有没有办法,我可以明确地设置的方式Content-Type为GET使用HttpClient的操作?
在实例化HttpClient时,一个常见的建议是:
但是,根据这个链接我看到评论,我认为这意味着另一个规则:
HttpClient类实例充当发送HTTP请求的会话.HttpClient实例是应用于该实例执行的所有请求的设置集合.此外,每个HttpClient实例都使用自己的连接池,将其请求与其他HttpClient实例执行的请求隔离开来.
这让我想知道我是否应该为每个与之交互的服务端点创建一个HttpClient实例.通过"服务端点",我的意思是一个不同的基地址.以下各项将是一个独特的"服务端点":
当然,如果我打算使用HttpClient的"BaseAddress"属性,并且如果我正在处理并发调用,那么我将需要每个"service-endpoint"有一个HttpClient实例.
但是,HttpClient允许我明确指定一个绝对地址:
HttpClient client = new HttpClient(...);
client.PostAsJsonAsync("http://foo.net/api/Message/", ...);
client.PostAsJsonAsync("http://bar.com/api/Message/", ...);
client.PostAsJsonAsync("http://wow.gov/api/Message/", ...);
client.PostAsJsonAsync("http://now.com/api/Message/", ...);
client.PostAsJsonAsync("http://mom.org/api/Message/", ...);
client.PostAsJsonAsync("http://dog.com/api/Message/", ...);
Run Code Online (Sandbox Code Playgroud)
上面的代码工作,它正是我想要的当前应用程序我正在构建.但是唠叨的问题仍然存在......如果我将一个HttpClient用于我的应用程序与之通信的所有服务端点,那么我做错了什么?
有没有理由我真的需要上面引文中提到的"连接池隔离"?
有没有办法向 IHttpClientFactory 创建的所有客户端添加处理程序?我知道您可以对指定客户执行以下操作:
services.AddHttpClient("named", c =>
{
c.BaseAddress = new Uri("TODO");
c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
c.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MaxAge = new TimeSpan(0),
MustRevalidate = true
};
}).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
});
Run Code Online (Sandbox Code Playgroud)
但我不想使用命名客户端,我只想向通过以下方式返回给我的所有客户端添加一个处理程序:
clientFactory.CreateClient();
Run Code Online (Sandbox Code Playgroud) 在我的 .net core Web api 项目中,我想使用外部 API,以便获得预期的响应。
我注册和使用 HttpClient 的方式如下。在启动中,我添加了以下代码,称为命名类型 httpclient 方式。
services.AddHttpClient<IRecipeService, RecipeService>(c => {
c.BaseAddress = new Uri("https://sooome-api-endpoint.com");
c.DefaultRequestHeaders.Add("x-raay-key", "123567890754545645gggg");
c.DefaultRequestHeaders.Add("x-raay-host", "sooome-api-endpoint.com");
});
Run Code Online (Sandbox Code Playgroud)
除此之外,我还有 1 个服务,我在其中注入了 HttpClient。
public class RecipeService : IRecipeService
{
private readonly HttpClient _httpClient;
public RecipeService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<List<Core.Dtos.Recipes>> GetReBasedOnIngAsync(string endpoint)
{
using (var response = await _httpClient.GetAsync(recipeEndpoint))
{
// ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
创建 httpClient 时,如果我将鼠标悬停在对象本身上,则基本 URI/标头会丢失,并且我不明白为什么会发生这种情况。如果有人能透露一些信息,我将不胜感激:)
第一次更新
该服务正在如下所示的控制器之一中使用。该服务由 DI 注入,然后将相对路径解析为该服务(我假设我已经将基本 URL 存储在客户端中)也许我做错了?
namespace ABC.Controllers
{
[ApiController]
[Route("[controller]")] …Run Code Online (Sandbox Code Playgroud) c# asp.net-web-api dotnet-httpclient asp.net-core-webapi httpclientfactory
c# ×9
.net ×4
json ×2
.net-4.5 ×1
asp.net-core ×1
content-type ×1
httpclient ×1
unit-testing ×1