I am figuring out performance of my C# web api. I wrote a very simple HelloWorld response:
public class HelloWorldController : ApiController
{
public HttpResponseMessage Get()
{
return new HttpResponseMessage()
{
Content = new StringContent("HelloWorld")
};
}
}
I tested by using JMeter I set 1000 Users request and it worked perfectly (CPU usage up to 100%). But the problem is that when the operation of the api take bit longer, the response become worse, got only 3 responses each (CPU usage <7%). It took minuets for 1000 users request.
public HttpResponseMessage Get()
{
Thread.Sleep(1000);
return new HttpResponseMessage()
{
Content = new StringContent("HelloWorld")
};
}
After google I come up with idea of using async but still I got same problem. I don't know what the problem is or my code implementation. Below is my sample implementation.
public async Task<HttpResponseMessage> Get()
{
return new HttpResponseMessage()
{
Content = new StringContent(await LongOperationAsync())
};
}
private string LongOperation()
{
//long operation here
Thread.Sleep(1000);
return "HelloWorld";
}
private Task<string> LongOperationAsync()
{
return Task.Factory.StartNew(() => LongOperation());
}
Anyone know what is the problem or any idea regarding to this problem?
async and await are not magic bullets that just "mak teh codez moah awesomz". On ASP.NET, await enables your application to be more scalable (and respond to changes in scale more quickly) by making optimum use of the thread pool.
So, if you're freeing up a thread pool thread (await) but using up another thread pool thread (StartNew), you're not going to gain anything. In particular, exposing a fake-async method for a synchronous API is an antipattern.
If possible, the best solution is to make LongOperationAsync a naturally-asynchronous operation:
public async Task<HttpResponseMessage> Get()
{
return new HttpResponseMessage()
{
Content = new StringContent(await LongOperationAsync())
};
}
private async Task<string> LongOperationAsync()
{
//long operation here
await Task.Delay(1000);
return "HelloWorld";
}
If this isn't possible, then you may as well keep it synchronous. Using Task.Run (or even worse, StartNew) isn't going to help at all.
The Method LongOperationAsync And LongOperation also should be async :
private async Task<string> LongOperation()
{
//long operation here
await Task.Delay(1000);
return "HelloWorld";
}
private async Task<string> LongOperationAsync()
{
var rt = await Task.Run(() => LongOperation());
return rt;
}
see:
Asynchronous programming
Related
I have a console application in which I need to retrieve some data from 4 different sites. I placed each HTTP request in a task and I wait for them all to complete.
It was working when I only had to get data from 2 sites. but then I needed to add other sources of data and when adding 3 or more requests, the Task.WaitAll() hangs.
Below is my code.
The reason I ended up using Task.WaitAll() was because I need to stop and prevent the console application from exiting - i.e. I need to perform other tasks only after all the HTTP requests come back with data.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static Task[] tasks = new Task[3];
static void Main(string[] args)
{
try
{
Run();
}
catch (System.Exception ex)
{
}
}
public static async void Run()
{
//works when using one or two tasks
tasks[0] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[1] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
//fails when add 3 or more task
tasks[2] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
//tasks[3] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
Task.WaitAll(tasks);
var result4 = ((Task<Stream>)tasks[2]).Result;
}
}
public static class HttpExtensions
{
public static Stopwatch sw;
public static long http_ticks = 0;
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request)
{
var taskComplete = new TaskCompletionSource<HttpWebResponse>();
request.BeginGetResponse(asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
}, request);
return taskComplete.Task;
}
public static async Task<Stream> GetMyData(string urlToCall)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToCall);
request.Method = HttpMethod.Get;
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
//using (var sr = new StreamReader(response.GetResponseStream()))
//{
return response.GetResponseStream();
//}
}
}
public static class HttpMethod
{
public static string Head { get { return "HEAD"; } }
public static string Post { get { return "POST"; } }
public static string Put { get { return "PUT"; } }
public static string Get { get { return "GET"; } }
public static string Delete { get { return "DELETE"; } }
public static string Trace { get { return "TRACE"; } }
public static string Options { get { return "OPTIONS"; } }
public static string Connect { get { return "CONNECT"; } }
public static string Patch { get { return "PATCH"; } }
}
}
There a number of concerns.
First, as I mentioned in the comments above, by not returning a Task you are more or less hanging your application since it can't tell when the Task is completed.
However, once you change the Run() method to return a task, you need to invoke it via a Task.Run call in your Main method.
Second, you are over-complicating your code by using WebClient. Switch to HttpClient and take advantage of its natural async/await API.
Third, you aren't actually awaiting anything in your Run() method so changing it to a task does nothing since you aren't awaiting a result which will cause it to run synchronously (no pun intended). Update your method to await a result.
Finally, WaitAll blocks the thread, which may not be what you want. You can use WhenAll instead and await that call, allowing your application to release the thread while your tasks run.
Below is a complete, working example of my recommended modifications, simplified to show a working program. The Main method recommendation is taken from https://social.msdn.microsoft.com/Forums/vstudio/en-US/fe9acdfc-66cd-4b43-9460-a8053ca51885/using-new-asyncawait-in-console-app?forum=netfxbcl
class Program
{
static Task[] tasks = new Task[3];
static HttpClient _client = new HttpClient();
static void Main(string[] args)
{
Console.WriteLine("Main start");
Task t = Run();
t.ContinueWith((str) =>
{
Console.WriteLine(str.Status.ToString());
Console.WriteLine("Main end");
});
t.Wait();
}
public static async Task Run()
{
tasks[0] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[1] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[2] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
await Task.WhenAll(tasks);
var result4 = (await (Task<Stream>)tasks[2]);
}
public static async Task<Stream> GetMyData(string urlToCall)
{
return await _client.GetStreamAsync(urlToCall);
}
}
I think the issue is more of understanding Task and async await; and I may be wrong so apologies up front.
Task is a managed thread that goes into a thread pool. Task has a Task.Result of Type T.
You can create a Task and then Start it and then Wait it. (Never a good idea to start and then immediately wait a task but for understanding...)
var task = new Task(() => DoWork());
task.Start();
task.Wait();
The task will perform the DoWork() method in a new thread.
The calling thread will BLOCK at task.Wait();
You can also give a Task a ContinueWith Action that will perform the remaining work on the calling thread.
var task = new Task(() => DoWorkOnNewThread());
task.ContinueWith(() => MainThreadWork());
task.Start(); //Notice no more task.Wait();
So, if you're following that little bit then you can sort of use async await correctly.
The async keyword tells the compiler to wrap all remaing code AFTER reaching the await keyword WHERE A GetAwaiter() is returned. This is important because until you actually create a task (preferably started also) and return it then you have no GetAwaiter();
private Task DoWorkAsync()
{
var task = new Task(() => DoWork());
task.Start();
return task;
}
private async void Method()
{
//Main thread code...
await DoWorkAsync(); //Returns to whoever called Method()
//More main thread code to be QUEUED to run AFTER DoWorkAsync is complete.
//This portion of code, when compiled, is essentially wrapped in the ContinueWith(...
}
So if you're still following along then here's the kicker. You're on the same thread UNTIL you return a GetAwaiter() which is only found in a Task. If the Task has never started then you'll await that Task forever technically. So here's some comments showing the thread transitions.
private Task DoWorkAsync()
{
Debug.WriteLine("Still on main thread")
var task = new Task(() =>
{
Debug.WriteLine("On background thread");
});
task.Start(); //On main thread.
return task; //On main thread.
}
private async void Method()
{
Debug.WriteLine("On main thread");
await DoWorkAsync(); //returns to caller after DoWorkAsync returns Task
Debug.WriteLine("Back on main thread"); //Works here after the task DoWorkAsync returned is complete
}
An easier way to return the task running is to return Task.Run(() => DoWork()); If you look at the return value of Run it is Task and that task has already been started.
Forgive me if this isn't what you wanted but I felt like there is more of a confusion about using async await correctly than there is confusion about your code. I may be wrong but I felt that if you could understand more about the Task itself and how async await works you would see your issue. If this isn't what you're looking for I'll delete the answer.
This is only the idea on what im doing in a window service.
I get the idea from this video to do it in parallel processing.
I have two different method and a model class.
Model Class code:
public class Email(){
public string Recipient { get; set; }
public string Message { get; set; }
}
Methods is something like this:
public void LoadData(){
while(Main.IsProcessRunning){
// 1. Get All Emails
var emails = new dummyRepositories().GetAllEmails(); //This will return List<Emails>.
// 2. Send it
// After sending assume that the data will move to other table so it will not be query again for the next loop.
SendDataParallel(emails);//this will function async? even though the calling method is sync.
// This will continue here or wait until it already send?
// If it will continue here even though it will not send already
// So there's a chance to get the email again for the next loop and send it again?
}
}
//This will send email at parallel
public async void SendDataParallel(IList<Email> emails){
var allTasks = emails.Select(SendDataAsync);
await TaskEx.WhenAll(allTasks);
}
//Assume this code will send email asynchronously. (this will not send email, for sample only)
public async void SendDataAsync(Email email){
using (var client = new HttpClient())
{
client.PostAsync(email);
}
}
I only want to get all queued emails then send it in parallel then wait until it already send.
I'm avoiding using foreach on every email that I get.
Lets start at the bottom:
You dispose your client before you actually finish receiving the HttpResponseMessage asynchronously. You'll need to make your method async Task and await inside:
public async Task SendDataAsync(Email email)
{
using (var client = new HttpClient())
{
var response = await client.PostAsync(email);
}
}
Currently, your SendDataParallel doesn't compile. Again, it needs to return a Task:
public Task SendEmailsAsync(IList<Email> emails)
{
var emailTasks = emails.Select(SendDataAsync);
return Task.WhenAll(allTasks);
}
At the top, you'll need to await on SendEmailsAsync:
public async Task LoadDataAsync()
{
while (Main.IsProcessRunning)
{
var emails = new dummyRepositories().GetAllEmails();
await SendEmailsAsync(emails);
}
}
Edit:
If you're running this inside a windows service, you can offload it to Task.Run and use the async keyword:
var controller = new Controller();
_processThread = Task.Run(async () => await controller.LoadDataAsync());
Doesn't your compiler highlight your code with errors?
If you mark your method as async while it doesn't return any value, you should set your return type as Task, not void:
public async Task SendDataParallel(IList<Email> emails){
var allTasks = emails.Select(SendDataAsync);
await Task.WhenAll(allTasks);
}
Your second method also shoud return a Task, otherwise what you want to (a)wait in the first method?
public async Task SendDataAsync(Email email){
using (var client = new HttpClient())
{
return client.PostAsync(email);
}
}
Now you can Select all your SendDataAsync tasks in SendDataParallel and .Wait() it's task in LoadData in synchronious mode:
public void LoadData(){
while(Main.IsProcessRunning){
var emails = new dummyRepositories().GetAllEmails(); //This will return List<Emails>.
SendDataParallel(emails).Wait();
}
}
More information you can find reading answers in other SO questions and docs on MSDN:
Can somebody please explain async / await?
Brief explanation of Async/Await in .Net 4.5
how to and when use async and await
Asynchronous Programming with Async and Await
And as you used LINQ's Select() which is based on foreach cycle next article also could be useful:
Nested task inside loop
I often write code that has convenience methods which basically wrap other methods. Here's a simple example:
public class WithoutAsync
{
public static ReadOnlyCollection<Response> GetResponses(IEnumerable<Request> fromRequests)
{
var ret = new List<Response>();
foreach (Request r in fromRequests)
{
ret.Add(new Response());
}
return ret.AsReadOnly();
}
//convenience method
public static Response GetResponse(Request fromRequest)
{
return GetResponses(new Request[] {fromRequest})[0];
}
}
Now I want to await long-running operations but I can't quite figure out how to retrofit this methodology for use with TPL:
public class WithAsync
{
public static async Task<ReadOnlyCollection<Response>> GetResponses(IEnumerable<Request> fromRequests)
{
var awaitableResponses = new List<Task<Response>>();
foreach (Request r in fromRequests)
{
awaitableResponses.Add(Task.Run<Response>(async () =>
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}));
}
return new List<Response>(await Task.WhenAll(awaitableResponses)).AsReadOnly();
}
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return GetResponse(new Request[] { fromRequest });
}
}
The convenience method above obviously won't work because it's trying to return a Task<ReadOnlyCollection<Response>> when it really needs to return a Task<Response>.
This works:
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return new Task<Response>(new Func<Response>(() => GetResponse(new Request[] { fromRequest }).Result[0]));
}
but it seems really awkward, and more importantly, it blocks on .Result[0] which is potentially on a UI thread.
Is there any good way to accomplish what I'm trying to do?
You're trying to avoid making that "convenience method" async, but there's no reason to do that.
What you want is to call the other method, wait until there are responses and then get the first and only one. You can do that by making it async and using await:
async Task<Response> GetResponseAsync(Request fromRequest)
{
var responses = await GetResponsesAsync(new[] { fromRequest });
return responses.Single();
}
Although a better solution in this specific case is to switch things around and have the single GetResponse actually do that work of a single request, and have the multiple GetRsponses call it instead:
async Task<ReadOnlyCollection<Response>> GetResponsesAsync(IEnumerable<Request> fromRequests)
{
return (await Task.WhenAll(fromRequests.Select(GetResponse))).ToList().AsReadOnly();
}
async Task<Response> GetResponseAsync(Request fromRequest)
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}
Notes:
I know it's an example, but there's probably no reason to use Task.Run instead of a simple async call.
The convention is to name async methods with an "Async" suffix (i.e. GetResponseAsync).
I've also pluralized the name of the method that returns a collection.
I'm still sticking with I3arnon's answer because it's a well-written, informative answer, but I'd like to submit my own answer because I realized that I was almost there. Here's the async convenience method I was struggling to find:
//convenience method
public static async Task<Response> GetResponse(Request fromRequest)
{
return (await GetResponses(new Request[] { fromRequest }))[0];
}
I have identified a bottleneck in my TCP application that I have simplified for the sake of this question.
I have a MyClient class, that represents when a client connects; also I have a MyWrapper class, that represents a client that fulfill some conditions. If a MyClientfulfill some conditions, it qualifies for wrapper.
I want to expose an method that allows the caller to await a MyWrapper, and that method should handle the negotiation and rejection of invalid MyClients:
public static async Task StartAccepting(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
var wrapper = await AcceptWrapperAsync(token);
HandleWrapperAsync(wrapper);
}
}
Therefore AcceptWrapperAsync awaits a valid wrapper, and HandleWrapperAsync handles the wrapper asynchronously without blocking the thread, so AcceptWrapperAsync can get back to work as fast as it can.
How that method works internally is something like this:
public static async Task<MyWrapper> AcceptWrapperAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
var client = await AcceptClientAsync();
if (IsClientWrappable(client))
return new MyWrapper(client);
}
return null;
}
public static async Task<MyClient> AcceptClientAsync()
{
await Task.Delay(1000);
return new MyClient();
}
private static Boolean IsClientWrappable(MyClient client)
{
Thread.Sleep(500);
return true;
}
This code simulates that there is a client connection every second, and that it takes half a second to checkout if the connection is suitable for a wrapper. AcceptWrapperAsync loops till a valid wrapper is generated, and then returns.
This approach, that works well, has a flaw. During the time that IsClientWrappable is executing, no further clients can be accepted, creating a bottleneck when lot of clients are trying to connect at the same time. I am afraid that in real life, if the server goes down while having lot of clients connected, the going up is not gonna be nice because all of them will try to connect at the same time. I know that is very difficult to connect all of them at the same time, but I would like to speed up the connection process.
Making IsClientWrappable async, would just ensure that the executing thread is not blocked till the negotiation finishes, but the execution flow is blocked anyway.
How could I improve this approach to continuously accept new clients but still be able of awaiting a wrapper using AcceptWrapperAsync?
//this loop must never be blocked
while (!token.IsCancellationRequested)
{
var client = await AcceptClientAsync();
HandleClientAsync(client); //must not block
}
Task HandleClientAsync(Client client) {
if (await IsClientWrappableAsync(client)) //make async as well, don't block
await HandleWrapperAsync(new MyWrapper(client));
}
This way you move the IsClientWrappable logic out of the accept loop and into the background async workflow.
If you do not wish to make IsClientWrappable non-blocking, just wrap it with Task.Run. It is essential that HandleClientAsync does not block so that its caller doesn't either.
TPL Dataflow to the rescue. I have created a "producer/consumer" object with two queues that:
accepts inputs from "producer" and stores it in the "in" queue.
a internal asynchronous task read from the "in" queue and process the input in parallel with a given maximum degree of parallelism.
put the processed item in the "out" queue afterwards. Result or Exception.
accepts a consumer to await an item. Then can check if the processing was successful or not.
I have done some testing and it seems to work fine, I want to do more testing though:
public sealed class ProcessingResult<TOut>
where TOut : class
{
public TOut Result { get; internal set; }
public Exception Error { get; internal set; }
}
public abstract class ProcessingBufferBlock<TIn,TOut>
where TIn:class
where TOut:class
{
readonly BufferBlock<TIn> _in;
readonly BufferBlock<ProcessingResult<TOut>> _out;
readonly CancellationToken _cancellation;
readonly SemaphoreSlim _semaphore;
public ProcessingBufferBlock(Int32 boundedCapacity, Int32 degreeOfParalellism, CancellationToken cancellation)
{
_cancellation = cancellation;
_semaphore = new SemaphoreSlim(degreeOfParalellism);
var options = new DataflowBlockOptions() { BoundedCapacity = boundedCapacity, CancellationToken = cancellation };
_in = new BufferBlock<TIn>(options);
_out = new BufferBlock<ProcessingResult<TOut>>(options);
StartReadingAsync();
}
private async Task StartReadingAsync()
{
await Task.Yield();
while (!_cancellation.IsCancellationRequested)
{
var incoming = await _in.ReceiveAsync(_cancellation);
ProcessThroughGateAsync(incoming);
}
}
private async Task ProcessThroughGateAsync(TIn input)
{
_semaphore.Wait(_cancellation);
Exception error=null;
TOut result=null;
try
{
result = await ProcessAsync(input);
}
catch (Exception ex)
{
error = ex;
}
finally
{
if(result!=null || error!=null)
_out.Post(new ProcessingResult<TOut>() { Error = error, Result = result });
_semaphore.Release(1);
}
}
protected abstract Task<TOut> ProcessAsync(TIn input);
public void Post(TIn item)
{
_in.Post(item);
}
public Task<ProcessingResult<TOut>> ReceiveAsync()
{
return _out.ReceiveAsync();
}
}
So the example I used on the OP would be something like this:
public class WrapperProcessingQueue : ProcessingBufferBlock<MyClient, MyWrapper>
{
public WrapperProcessingQueue(Int32 boundedCapacity, Int32 degreeOfParalellism, CancellationToken cancellation)
: base(boundedCapacity, degreeOfParalellism, cancellation)
{ }
protected override async Task<MyWrapper> ProcessAsync(MyClient input)
{
await Task.Delay(5000);
if (input.Id % 3 == 0)
return null;
return new MyWrapper(input);
}
}
And then I could add MyClient objects to that queue as fast as I get them, they would be processed in parallel, and the consumer would await for the ones that pass the filter.
As I said, I want to do more testing but any feedback will be very welcomed.
Cheers.
I'm trying to start async task (on .NET 4.5) which downloads content of web page, but somehow this task never finishes.
My PageDownloader class:
using System.Net;
using System.Text;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System;
namespace ParserConsole.WebClient
{
public class PageDownloader
{
private System.Net.Http.HttpClient _client;
public PageDownloader()
: this(Encoding.UTF8) { }
private Encoding _encoding;
public PageDownloader(Encoding encoding)
{
_encoding = encoding;
_client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10)};
}
private HttpRequestMessage _request;
private HttpResponseMessage _response;
private string _responseString;
public string GetPageData(string link)
{
_request = new HttpRequestMessage(HttpMethod.Get, link);
_request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
_request.Headers.Add("Accept", "text/html");
GetResponse().Wait();
GetStringFromResponse().Wait();
return _responseString;
}
private async Task<HttpResponseMessage> GetResponse() {
return _response = await _client.GetAsync(_request.RequestUri);
}
private async Task<string> GetStringFromResponse() {
return _responseString = await _response.Content.ReadAsStringAsync();
}
}
}
I start downloading page by calling
new PageDownloader().GetPageData(url);
When I'm trying to debug the code, everything is fine till GetResponse().Wait(). But somehow GetResponse() task never finishes - breakpoint on the next line is never reached. I get no exceptions, application continues running. Any suggestions?
This is a standard deadlock condition you get when you start an async operation and then block on the returned task.
Here is a blog post discussion the topic.
Basically, the await call ensures that the continuation it wires up of the task will run in the context you were originally in (which is very helpful) but because you are calling Wait in that same context it's blocking, so the continuation never runs, and that continuation needs to run for the wait to end. Classic deadlock.
As for the fix; usually it means you just shouldn't be doing a blocking wait on the async operation; it's contrary to the design of the whole system. You should, "async all the way up". In this case it would mean that GetPageData should return a Task<string> rather than a string, and rather than waiting on the other operations that return a task you should await on them.
Now, having said that, there are ways of doing a blocking wait on the async operations without deadlocking. While it can be done, it honestly defeats the purpose of using async/await in the first place. The primary advantage of using that system is that the main context isn't blocked; when you block on it that entire advantage goes away, and you might as well just use blocking code all the way through. async/await is really more of an all-or-nothing paradigm.
Here is how I would structure that class:
public class PageDownloader
{
private System.Net.Http.HttpClient _client;
private Encoding _encoding;
public PageDownloader()
: this(Encoding.UTF8) { }
public PageDownloader(Encoding encoding)
{
_encoding = encoding;
_client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
}
public async Task<string> GetPageData(string link)
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, link);
request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
request.Headers.Add("Accept", "text/html");
HttpResponseMessage response = await _client.GetAsync(request.RequestUri);
return await response.Content.ReadAsStringAsync(); ;
}
}
Why not just do this if you want to have a function like that.
public string GetPageData(string link)
{
_request = new HttpRequestMessage(HttpMethod.Get, link);
_request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
_request.Headers.Add("Accept", "text/html");
var readTask = _client.GetStringAsync(link);
readTask.Wait();
return readTask.Result;
}
It would be better to return the Task all the way back and handle it with async/await in the calling code.
public Task<string> GetPageData(string link)
{
_request = new HttpRequestMessage(HttpMethod.Get, link);
_request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
_request.Headers.Add("Accept", "text/html");
return _client.GetStringAsync(link);
}