How to run asynchronous methods inside my ActionResult in MVC, c# - c#

I'm getting data from a web service.it took bit time. this is my controller
{
// THERE SO MANY FUNCTIONS BEFORE THIS.
//
try
{
string serviceUrl = "https://www.myserviceweb.com/assets/webhandler/details.ashx";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(serviceUrl);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader sr = new StreamReader(resp.GetResponseStream());
string result = sr.ReadToEnd();
sr.Close();
var rootResult = XElement.Parse(result);
System.Web.HttpContext.Current.Session["rootvss"] = rootResult;
}
catch (Exception ex)
{
Debug.WriteLine("error");
}
return View();
}
before I call to this function, there are lot functions. so altogether it took more time to load the index.what I want to do is
To run only above function asynchronously. how can I do that. I tried to use method like following.but I do not know how to use it.
public async Task webservce()
{
}
hope your help with this

if you want use Async , that structure like this :
public async Task<ActionResult> webservce()
{
return await _yourService.GetAllAsync(); // here you should call Async Methods like .ToListAsync ,...
}

All is explained on msdn here : https://msdn.microsoft.com/en-us/library/hh300224.aspx

Related

c# error with calling async method - "Could not load type '<deleteCommands>d__2' from assembly

So, I'm really a PHP developer, so no doubt this is a really obvious thing I'm missing.
I seem to be having problem with running async methods - I've tried a couple of ways (using await, using a Task), and I keep getting the above error whenever calling a method that is async..
The function as it stands currently is ...
public async static void deleteCommands(List<int> commandIds)
{
Tebex.logWarning("Async Delete....");
await Task.Run(() =>
{
String url = "http://www.example.com/" + "queue?";
String amp = "";
foreach (int CommandId in commandIds)
{
url = url + amp + "ids[]=" + CommandId;
amp = "&";
}
Tebex.logWarning("DELETE " + url);
var request = WebRequest.Create(url);
request.Method = "DELETE";
request.Headers.Add("APIKey", "myApiKey");
var response = (HttpWebResponse) request.GetResponse();
Tebex.logWarning(response.ToString());
}).ConfigureAwait(false);
}
and I'm calling it from another method (I don't need the response or anything, it's a fire-and-forget method)
try
{
deleteCommands(executedCommands);
executedCommands.Clear();
}
catch (Exception ex)
{
Tebex.logError(ex.ToString());
}
Previously I was using await request.getResponseAsync() but I received the same error -
public async static void deleteCommands(List<int> commandIds)
{
Tebex.logWarning("Async Delete....");
String url = "http://www.example.com/" + "queue?";
String amp = "";
foreach (int CommandId in commandIds)
{
url = url + amp + "ids[]=" + CommandId;
amp = "&";
}
Tebex.logWarning("DELETE " + url);
var request = WebRequest.Create(url);
request.Method = "DELETE";
request.Headers.Add("APIKey", "myApiKey");
await request.GetResponseAsync();
request = null;
}
As I mentioned, I'm probably missing something obvious, but I can't figure out what!
I'm not sure if any of this resolves your exception, but it should be changed regardless.
Instead of returning void you should return Task from deleteCommands. More on that here: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx?f=255&MSPPError=-2147217396
Depending on how your calling method looks, and how you'd like thread-management to function, there are a couple of solutions:
The preferred:
await deleteCommands(executedCommands);
This requires a async method though.
If you really want to use Task.Run (forces a new thread. Considder the load), then use it when calling the method instead:
Task.Run(async () => await deleteCommands(executedCommands));
Additionaly if you have an async method it, and all following calls, should also follow the async pattern. Switch to async WebRequests and use an async logger.
You should not clear the executedCommands list immediately because it is a fire and forget method (list can be cleared before the method finishes execution)
You should use ContinueWith instead
deleteCommands(executedCommands)
.ContinueWith(r => executedCommands.Clear());

C#: Crawl a page with asynchronous method

I'm coding a plug-in for Excel. I'd like to add a new method to excel that can crawl a web page and get back the html code.
my problem is that i have a lot of URLs to proces and if I use a sync method, it will take a lot of time and freeze my excel.
let say, i have a cell A1 which contains "http://www.google.com", and in A2, my method "=downloadHtml(A1)".
I'm using HttpClient because it is already handling Async. So here is my code :
static void Main()
{
GetWebPage(new Uri("http://www.google.com"));
}
static async void GetWebPage(Uri URI)
{
string html = await HttpGetAsync(URI);
//Do other operations with html code
Console.WriteLine(html);
}
static async Task<string> HttpGetAsync(Uri URI)
{
try
{
HttpClient hc = new HttpClient();
Task<Stream> result = hc.GetStreamAsync(URI);
Stream vs = await result;
StreamReader am = new StreamReader(vs);
return await am.ReadToEndAsync();
}
catch (WebException ex)
{
switch (ex.Status)
{
case WebExceptionStatus.NameResolutionFailure:
Console.WriteLine("domain_not_found");
break;
//Catch other exceptions here
}
}
return "";
}
The probem is that, when i run the program, the program exits before the task complete.
If i add a
Console.ReadLine();
the program will not exit do to the readline instruction, and after a couple of seconds, i see the html printed into my screen (du to the console.writeline instruction). So the program works.
how can i handle this ?
GetWebPage is a fire-and-forget method (an async void), so you cannot wait for it to finish.
You should be using this instead:
static void Main()
{
string html = Task.Run(() => HttpGetAsync(new Uri("http://www.google.com"))).GetAwaiter().GetResult();
//Do other operations with html code
Console.WriteLine(html);
}
Also, you could simplify the download code to this:
using (var HttpClient hc = new HttpClient())
{
return await hc.GetStringAsync(URI);
}

How to stream with ASP.NET Core

How to properly stream response in ASP.NET Core?
There is a controller like this (UPDATED CODE):
[HttpGet("test")]
public async Task GetTest()
{
HttpContext.Response.ContentType = "text/plain";
using (var writer = new StreamWriter(HttpContext.Response.Body))
await writer.WriteLineAsync("Hello World");
}
Firefox/Edge browsers show
Hello World
, while Chrome/Postman report an error:
The localhost page isn’t working
localhost unexpectedly closed the connection.
ERR_INCOMPLETE_CHUNKED_ENCODING
P.S. I am about to stream a lot of content, so I cannot specify Content-Length header in advance.
To stream a response that should appear to the browser like a downloaded file, you should use FileStreamResult:
[HttpGet]
public FileStreamResult GetTest()
{
var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));
return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))
{
FileDownloadName = "test.txt"
};
}
#Developer4993 was correct that to have data sent to the client before the entire response has been parsed, it is necessary to Flush to the response stream. However, their answer is a bit unconventional with both the DELETE and the Synchronized.StreamWriter. Additionally, Asp.Net Core 3.x will throw an exception if the I/O is synchronous.
This is tested in Asp.Net Core 3.1:
[HttpGet]
public async Task Get()
{
Response.ContentType = "text/plain";
StreamWriter sw;
await using ((sw = new StreamWriter(Response.Body)).ConfigureAwait(false))
{
foreach (var item in someReader.Read())
{
await sw.WriteLineAsync(item.ToString()).ConfigureAwait(false);
await sw.FlushAsync().ConfigureAwait(false);
}
}
}
Assuming someReader is iterating either database results or some I/O stream with a large amount of content that you do not want to buffer before sending, this will write a chunk of text to the response stream with each FlushAsync().
For my purposes, consuming the results with an HttpClient was more important than browser compatibility, but if you send enough text, you will see a chromium browser consume the results in a streaming fashion. The browser seems to buffer a certain quantity at first.
Where this becomes more useful is with the latest IAsyncEnumerable streams, where your source is either time or disk intensive, but can be yielded a bit at at time:
[HttpGet]
public async Task<EmptyResult> Get()
{
Response.ContentType = "text/plain";
StreamWriter sw;
await using ((sw = new StreamWriter(Response.Body)).ConfigureAwait(false))
{
await foreach (var item in GetAsyncEnumerable())
{
await sw.WriteLineAsync(item.ToString()).ConfigureAwait(false);
await sw.FlushAsync().ConfigureAwait(false);
}
}
return new EmptyResult();
}
You can throw an await Task.Delay(1000) into either foreach to demonstrate the continuous streaming.
Finally, #StephenCleary 's FileCallbackResult works the same as these two examples as well. It's just a bit scarier with the FileResultExecutorBase from deep in the bowels of the Infrastructure namespace.
[HttpGet]
public IActionResult Get()
{
return new FileCallbackResult(new MediaTypeHeaderValue("text/plain"), async (outputStream, _) =>
{
StreamWriter sw;
await using ((sw = new StreamWriter(outputStream)).ConfigureAwait(false))
{
foreach (var item in someReader.Read())
{
await sw.WriteLineAsync(item.ToString()).ConfigureAwait(false);
await sw.FlushAsync().ConfigureAwait(false);
}
}
outputStream.Close();
});
}
It is possible to return null or EmptyResult() (which are equivalent), even when previously writing to Response.Body. It may be useful if the method returns ActionResult to be able to use all the other results aswell (e.g. BadQuery()) easily.
[HttpGet("test")]
public ActionResult Test()
{
Response.StatusCode = 200;
Response.ContentType = "text/plain";
using (var sw = new StreamWriter(Response.Body))
{
sw.Write("something");
}
return null;
}
I was wondering as well how to do this, and have found out that
the original question's code actually works OK on ASP.NET Core 2.1.0-rc1-final, neither Chrome (and few other browsers) nor JavaScript application do not fail with such endpoint.
Minor things I would like to add are just set StatusCode and close the response Stream to make the response fulfilled:
[HttpGet("test")]
public void Test()
{
Response.StatusCode = 200;
Response.ContentType = "text/plain";
using (Response.Body)
{
using (var sw = new StreamWriter(Response.Body))
{
sw.Write("Hi there!");
}
}
}
This question is a bit older, but I couldn't find a better answer anywhere for what I was trying to do. To send the currently buffered output to the client, you must call Flush() for each chunk of content you would like to write. Simply do the following:
[HttpDelete]
public void Content()
{
Response.StatusCode = 200;
Response.ContentType = "text/html";
// the easiest way to implement a streaming response, is to simply flush the stream after every write.
// If you are writing to the stream asynchronously, you will want to use a Synchronized StreamWriter.
using (var sw = StreamWriter.Synchronized(new StreamWriter(Response.Body)))
{
foreach (var item in new int[] { 1, 2, 3, 4, })
{
Thread.Sleep(1000);
sw.Write($"<p>Hi there {item}!</p>");
sw.Flush();
}
};
}
you can test with curl using the following command: curl -NX DELETE <CONTROLLER_ROUTE>/content
something like this might work:
[HttpGet]
public async Task<IActionResult> GetTest()
{
var contentType = "text/plain";
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World")))
return new FileStreamResult(stream, contentType);
}

C# Threading with functions that return variables

Okay so basically I have a function that returns a string, but to get that string it uses webrequest which means while it's doing that webrequest the form is locking up unless I put it in a different thread.
But I can't figure out a way to capture the returned data in a thread since it's started using thread.start and that's a void.
Any help please?
Current code if it matters to anyone:
string CreateReqThread(string UrlReq)
{
System.Threading.Thread NewThread = new System.Threading.Thread(() => CreateReq(UrlReq));
string ReturnedData = "";
return ReturnedData;
}
string CreateReq(string url)
{
try
{
WebRequest SendReq = WebRequest.Create(url);
SendReq.Credentials = CredentialCache.DefaultCredentials;
SendReq.Proxy = WebRequest.DefaultWebProxy; //For closed port networks like colleges
SendReq.Proxy.Credentials = CredentialCache.DefaultCredentials;
SendReq.Timeout = 15000;
System.IO.StreamReader Reader = new System.IO.StreamReader(SendReq.GetResponse().GetResponseStream());
string Response = Reader.ReadToEnd();
Reader.Close();
return Response;
}
catch (WebException e)
{
EBox(e.Message, "Unknown Error While Connecting");
return null;
}
}
A common means of doing this is to use a Task<T> instead of a thread:
Task<string> CreateReqThread(string UrlReq)
{
return Task.Factory.StartNew() => CreateReq(UrlReq));
// In .NET 4.5, you can use (or better yet, reimplement using await/async directly)
// return Task.Run(() => CreateReq(UrlReq));
}
You can then call Task<T>.Result to get the returned value (later), when it's needed, or schedule a continuation on the task which will run when it completes.
This could look something like:
var request = CreateReqThread(theUri);
request.ContinueWith(t =>
{
// Shove results in a text box
this.textBox.Text = t.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
This also works perfectly with the new await/async support in C# 5.

Async CTP method freeze when return value

Im trying to make an async method that returns a value. everything work when use the method without return. you can process data , but the problem appears when the return clause added. the program freeze completely without any error or for a while.
please see the code:
public void runTheAsync(){
string resp = sendRequest("http://google.com","x=y").Result;
}
public async Task<string> sendRequest(string url, string postdata)
{
//There is no problem if you use void as the return value , the problem appears when Task<string> used. the program fully go to freeze.
Console.WriteLine("On the UI thread.");
string result = await TaskEx.Run(() =>
{
Console.WriteLine("Starting CPU-intensive work on background thread...");
string work = webRequest(url,postdata);
return work;
});
return result;
}
public string webRequest(string url, string postdata)
{
string _return = "";
WebClient client = new WebClient();
byte[] data = Encoding.UTF8.GetBytes(postdata);
Uri uri = new Uri(url);
_return = System.Text.Encoding.UTF8.GetString(client.UploadData(uri, "POST", data));
return _return;
}
string resp = sendRequest("http://google.com","x=y").Result;
That's your problem. If you call Result on a Task, it blocks until the Task finishes.
Instead, you can do this:
public async void runTheAsync()
{
string resp = await sendRequest("http://google.com","x=y");
}
But creating async void methods should be avoided. Whether you actually can avoid it, depends on how are you calling it.
Try this, data correctness checks etc. omitted but you ignored them either :-):
public async Task<string> UploadRequestAsync(string url, string postdata)
{
string result = await Encoding.GetString(
new WebClient().UploadData(new Uri(uri), "POST", Encoding.UTF8.GetBytes(postdata)));
return result;
}
You somehow doing the work twice, awaiting a explicitly started task. I'd be curious to see what the generated code for this looks like... And of course, in production code use the proper classes from .NET 4.5.

Categories