Been stuck for days, hoping someone can help me.
I have been trying to run the YouTube 'Search by keyword' example from Google's API examples for .net in a VS 2013 Express for Web MVC4 project, and the ExecuteAsync() calling the Google API never comes back.
I believe the example code works as I tested it in VS 2013 Express for Windows Desktop as a console application and it came back fine. Also the stats in google's developers console tell me the API request is being received.
Here is what I did:
I created a new VS 2013 Express for Web MVC4 project called GoogleTest and installed the 'Install-Package Google.Apis.YouTube.v3' package.
I then added the following model.
public class SearchYouTube
{
public int ID { get; set; }
public async Task RunYouTube()
{
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
ApiKey = " <MY DEVELOPER KEY HERE> ",
ApplicationName = this.GetType().ToString()
});
var searchListRequest = youtubeService.Search.List("snippet");
searchListRequest.Q = "googleapi examples"; // Replace with your search term.
searchListRequest.MaxResults = 50;
// Call the search.list method to retrieve results matching the specified query term.
var searchListResponse = await searchListRequest.ExecuteAsync();
List<string> videos = new List<string>();
List<string> channels = new List<string>();
List<string> playlists = new List<string>();
// Add each result to the appropriate list, and then display the lists of
// matching videos, channels, and playlists.
foreach (var searchResult in searchListResponse.Items)
{
switch (searchResult.Id.Kind)
{
case "youtube#video":
videos.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.VideoId));
break;
case "youtube#channel":
channels.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.ChannelId));
break;
case "youtube#playlist":
playlists.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.PlaylistId));
break;
}
}
Console.WriteLine(String.Format("Videos:\n{0}\n", string.Join("\n", videos)));
Console.WriteLine(String.Format("Channels:\n{0}\n", string.Join("\n", channels)));
Console.WriteLine(String.Format("Playlists:\n{0}\n", string.Join("\n", playlists)));
}
}
Then I call the above class in the Home controller like so:
public ActionResult Index()
{
ViewBag.Message = "MVC example";
SearchYouTube searchObject = new SearchYouTube();
searchObject.RunYouTube().Wait();
return View();
}
Running this in the debugger, the program steps into but never returns from this line in the SearchYouTube class above:
var searchListResponse = await searchListRequest.ExecuteAsync();
Can anyone help explain what I am doing wrong or what I am missing??
You seem to have a deadlock on your hands because you're doing "sync over async". When you use Task.Wait you're blocking and wasting a thread. After the inner async operation (i.e. await searchListRequest.ExecuteAsync();) completes it evidently needs that same thread to continue processing the rest of the method.
All that happens because of the SynchronizationContext present in ASP.Net which is captured when await is used so that the continuation would be posted to it. When you use ConfigureAwait(false) you're configuring the continuation to not run on the captured context and use the ThreadPool instead.
In console apps there is no SC and so every continuation runs on the ThreadPool. It's as if every await had ConfigureAwait(false).
To solve this deadlock you can use ConfigureAwait(false) or even better, make the MVC method async so you don't need to block synchronously (more on async in MVC):
public async Task<ActionResult> Index()
{
ViewBag.Message = "MVC example";
SearchYouTube searchObject = new SearchYouTube();
await searchObject.RunYouTube();
return View();
}
Related
I have an ASP.NET MVC application from which I would like to consume an ASP.NET Web API REST service.
So I have found a piece of code here.
In my case I would like to call ASP.NET Web API method (DumpIntoFile) from a method in a class in my ASP.NET MVC app (this class is not a controller). I need the execution not to continue until call to DumpIntoFile is completed and finished. How can I do it? I have never used async and await so I do not understand at all how they work.
public void GetData()
{
Warehouse myData = new Warehouse();
myData.id = 1111;
myData.name = blabla;
string path = "c:\temp";
string filename = "myData.dat";
// Stuff here
this.DumpWarehouseDataIntoFile(myData, path, filename);
// Some other stuff here
}
public async void DumpWarehouseDataIntoFile(Warehouse myData, string path, string filename) // See Warehouse class later in this post
{
//Hosted web API REST Service base url
string Baseurl = "http://XXX.XXX.XX.X:YYYY/";
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Serialize parameter to pass to the asp web api rest service
string jsonParam = Newtonsoft.JsonConvert.SerializeObject(myData);
//Sending request to find web api REST service resource using HttpClient
// How can I pass parameters jsonParam, path and filename to below call??????? Concatenating it?
HttpResponseMessage Res = await client.GetAsync("api/Warehouse/DumpIntoFile");
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
// Some other sftuff here
}
}
}
The Warehouse object is as below:
public class Warehouse {
public Warehouse();
public int id { get; set; }
public string name { get; set; }
// some other stuff here
}
And web api rest controller with method:
public class MyWebApiController : ApiController
{
public bool DumpIntoFile(string data, string path, string filename)
{
bool result;
Warehouse myData = JsonConvert.DeserializeObject<Warehouse>(data);
string myPath = path;
string myFilename = filename;
// Here rest of code
return result;
}
}
Also I am trying to do below:
Avoid to hard-code the URL because if the ASP.NET Web API REST service is published in another server in a future, then I need to touch code, change it and publish again my ASP.NET MVC application. Maybe putting a the url in the web.config file and read from there?
How can I pass the parameters jsonParam, path and filename to the web api rest service? concatenating it?
NOTES:
I am using NET 4.5 and Visual Studio 2013.
How can I do it? I have never used async and await so I do not understand at all how they work.
I recommend you read my async intro and follow up with async best practices. You'll learn two key things:
Avoid async void.
It's normal for async/await to "grow" through your codebase.
In your case, DumpWarehouseDataIntoFile should be async Task instead of async void. And that means GetData needs to await the task returned from DumpWarehouseDataIntoFile. Which means GetData should also be async Task. Which means things calling GetData should use await, etc.
Side note: By convention, asynchronous methods should end in Async.
public async Task GetDataAsync()
{
Warehouse myData = new Warehouse();
myData.id = 1111;
myData.name = blabla;
string path = "c:\temp";
string filename = "myData.dat";
// Stuff here
await this.DumpWarehouseDataIntoFileAsync(myData, path, filename);
// Some other stuff here
}
public async Task DumpWarehouseDataIntoFileAsync(Warehouse myData, string path, string filename)
I am experimenting with an asynchronous call to an Azure Rest Api from a DNN module (this is for a client that uses the DNN platform and an older version of it namely 8.0). I need this call to retrieve the data before returning the View.
I made the controller async in order to be "await" getting the data from the azure rest api.
The behavior is unexpected. The code stops at this breakpoint(as in browser window with the blank view pops up but code after this point does not get executed) and the view is blank and never continues to the code populating the viewmodel for the page:
var result = await httpClient.GetStringAsync(url);
Sometimes result (the db user) is returned properly from the db, but the view is still blank even though the other breakpoints after await have been hit in the controller... The view seems to be returned before the await call is completed? The View window gets focus before await is completed but as a blank page.
Any suggestions about what is going on please?
In the DNN Controller class:
public async Task<ActionResult> Index() : DnnController
{
ViewModel pageVM = new ViewModel();
AuthenticationApi authService = new AuthenticationApi();
var outcome = await authService.GetDbUser(); // AWAIT
// populate the pageVM
.................
return View(pageVM);
}
In the Services folder, in the AuthenticationApi class:
public class AuthenticationApi
{
public async Task<DbUser> GetDbUser()
{
string url = "https://mywebservicename.azurewebsites.net/api/applicants/46";
var httpClient = new HttpClient();
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
try
{
var result = await httpClient.GetStringAsync(url);
return JsonConvert.DeserializeObject<DbUser>(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
}
The main response pipeline within DNN Platform is web-forms based and does not currently (even with version 9.6.2) support the usage of async/await in the main pipeline.
There is roadmap plans for this to be supported in version 10.x, however, additional changes are necessary to ensure that language features are not broken.
Some users have had success by adding this
aspnet:UseTaskFriendlySynchronizationContext
Application setting with a value of true, however, it is known to break certain features of DNN Platform such as Localization.
Hi Im new to MVC and still trying to understand the possible problem of using async.
I have the code below and as you can see i have placed async for all database calls (Not sure whether this is a good practice).
As you might notice this is a simple payment process. I am updating the CustomerPayment entity using the attribute of Customer and also once I added the new transaction, I am updating the balance attribute of the customer.
Using the colde below, will there be any risk of using async in regards to database calls ?
Also, I could see the _context.Database.BeginTransactionAsync() method for transaction, what will be the difference of using BeginTransactionAsync and normal BeginTransaction ?
Any chance this code can be re-written to properly use async ?
using (var dbContextTransaction = _context.Database.BeginTransaction())
{
try
{
CustomerPayment cp = vm;
Customer c = await _context.Customer.SingleOrDefaultAsync(m => m.CustomerId == vm.SelectedCustomerID);
decimal? updatedOutstandingAmount = c.CurrentOutStandingBalance - cp.Payment.PaymentAmount;
cp.OutstandingAmount = updatedOutstandingAmount;
c.CurrentOutStandingBalance = updatedOutstandingAmount;
_context.Add(cp);
_context.Update(c);
await _context.SaveChangesAsync();
dbContextTransaction.Commit();
TempData["status"] = "CustomerPaymentAdded";
return RedirectToAction("Payment", "Customer");
}
catch(Exception ex)
{
dbContextTransaction.Rollback();
}
};
I am working on a project (ASP.NET MVC 5) where I am using Umbraco 7.4.3. I am trying to implement the google analytics api along with oauth2. I used the sample code available on the google documentation platform. After authorizing with my google account I get a correct refresh token. But the problem is this refresh token is returned in the URL and is not getting passed by my controller to my view which remains empty. I have a feeling that my controller does not wait to execute it's code after the user authorized his or her google account hence the controller is not bothered about the await operator.
Link to the sample code
public class GoogleAnalyticsController : SurfaceController
{
public async Task<ActionResult> Add(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
var service = new AnalyticsService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "Analytics Dashboard"
});
// YOUR CODE SHOULD BE HERE..
ViewBag.AccessToken = result.Credential.Token.AccessToken;
ViewBag.RefreshToken = result.Credential.Token.RefreshToken;
var list = await service.Management.AccountSummaries.List().ExecuteAsync(cancellationToken);
ViewBag.Username = list.Username;
for (int i = 0; i < list.TotalResults; i++)
{
ViewBag.WebsiteNames += list.Items[i].Name + "(" + list.Items[i].WebProperties[0].WebsiteUrl + ")";
}
return View("~/Views/Configboard.cshtml");
}
else
{
return new RedirectResult(result.RedirectUri);
}
}
PS: I have tried this sample code out in a ASP.NET MVC 5 project without Umbraco installed which works perfectly.
Any one able to push me into the right direction?
For anyone else getting this problem, the solution was actually pretty simple:
I made a custom route for the AuthCallbackController (/authcallback/indexasync) and it all worked. Because Umbraco takes over the default routing this URL was not reachable hence the action of the authcallbackcontroller was not executed.
I just started playing around with RestSharp and WebApi and I've run into a little bit of an issue.
I'm not sure if this is best practice or even possible, but I'll demonstrate through code (this isn't my exact code but it's the exact same concept)
[HttpPost]
public HttpResponseMessage CreateEmployee(Employee emp, int employeeType)
{
// CREATE EMPLOYEE
return Request.CreateResponse(HttpStatusCode.Created, emp.id);
}
I've created a console app to test this using RestSharp. Here's what I have:
var client = new RestClient();
client.BaseUrl = #"http://localhost:15507";
var employee = new Employee();
//populate employee model
postrequest.Method = Method.POST;
postrequest.Resource = "api/Employee/CreateEmployee";
postrequest.AddHeader("Accept", "application/json");
postrequest.AddHeader("Content-Type", "application/json");
postrequest.RequestFormat = DataFormat.Json;
postrequest.AddBody(new { emp = employee, listId = 2 });
var res = client.Execute(postrequest);
The error that I get is that employeeType parameter comes in as null. Am I formatting this properly? Is this something that's even possible to do?
When i remove the employeeType parameter from the WebApi action method and modify the request to:
postrequest.AddBody(employee);
everything works fine.
any ideas? Thanks
if you are expecting employeetype from uri and if its not part of defined route, you can send it as query string parameter...Ex:
api/Employee/CreateEmployee?employeeType=