Invoke Task Method in an MVC Action but current Thread be Locked - task

public class HomeController : Controller
{
public ActionResult Index()
{
var t1= Test1().Result;
return View();
}
private async Task<HttpResponseMessage> Test1()
{
string strUrl = "http://localhost:52033/api/values";
var instanceClient = new HttpClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Get, strUrl);
var httpRespons = await instanceClient.SendAsync(requestMessage);
return httpRespons;
}
}
When I was in the Index Action called Test1 (). The Result; Will happen when the current thread deadlock program has been no response, do not bring the Result calls suffixes can normal operation!

You shouldn't call Result or Wait in an ASP.NET context; one reason is that it could cause deadlocks, as I explain on my blog.
Instead, you should use await, like this:
public async Task<ActionResult> Index()
{
var t1 = await Test1();
return View();
}

Related

How to get different response type for the same request model using MediatR?

I am trying to understand how MediatR works. Never used this library before. Below code is not actual production code. It is only for understanding purpose.
Lets say I have two RequestHandlers. Each handler takes ProductModel as request but returns different type of response.
public class GetOrdersHandler : IRequestHandler<ProductModel, IEnumerable<Order>>
{
private readonly FakeDataStore _fakeDataStore;
public GetOrdersHandler(FakeDataStore fakeDataStore)
{
_fakeDataStore = fakeDataStore;
}
public async Task<IEnumerable<Order>> Handle(ProductModel request,CancellationToken cancellationToken
{
return await _fakeDataStore.GetAllOrdersForProduct(request);
}
}
public class SaveProductHandler : IRequestHandler<ProductModel, Product>
{
private readonly FakeDataStore _fakeDataStore;
public SaveProductHandler(FakeDataStore fakeDataStore)
{
_fakeDataStore = fakeDataStore;
}
public async Task<Product> Handle(ProductModel request,CancellationToken cancellationToken)
{
return await _fakeDataStore.SaveProduct(request);
}
}
Then in the same controller I have two action methods
public class ProductsController : ControllerBase
{
private readonly IMediator _mediator;
public ProductsController(IMediator mediator) => _mediator = mediator;
[HttpPost]
public async Task<ActionResult> GetAllOrders(ProductModel model)
{
var product = await _mediator.Send(model);
return Ok(product);
}
[HttpPost]
public async Task<ActionResult> SaveProduct(ProductModel model)
{
var product = await _mediator.Send(model);
return Ok(product);
}
}
Based on the MediatR code this may not work. Looks like the Send method creates instance of handler based on Request type. It keeps dictionary of RequestType and corresponding handler.
If my assumption is correct then does that mean I will have to create unique request model for each action method that will be using Send method?

Testing a Mvc controller that gets data from an API endpoint

I am working on a Web project that gets data from an API endpoint. The API layer sits on top of Service Layer and Repository Layer at the bottom. I have written unit testing for the Service and API Layers. I am using Moq framework to mock dependencies.
Now i want to test the MVC controller. I am using a Request Manager class which is derived from HttpClient to get data from the API endpoints. So how do i test this controller. I have written a unit test but the test is getting data directly from my Database.
public class UserController : Controller
{
private RequestManager requestManager = new RequestManager();
// GET: User
public async Task<ActionResult> Index()
{
List<UserViewModel> allUsers = await requestManager.GetUsers();
if(allUsers == null)
{
throw new HttpException(404, "No Users Found");
}
return View(allUsers);
}
}
public class UserControllerTest
{
public UserController controller;
[OneTimeSetUp]
public void InIt()
{
controller = new UserController();
}
[Test]
public async Task TestIndex()
{
var view = await controller.Index() as ActionResult;
Assert.That(view is ViewResult);
Assert.That(view.Model is List<UserViewModel>);
}
}
You should decouple controller and manager. Extract interface from RequestManager and inject it into controller. That should not be a problem, Ioc container can do that for you.
public class UserController : Controller
{
private RequestManager _requestManager;
public UserController(IRequestManager requestManager)
{
_requestManager = requestManager;
}
// GET: User
public async Task<ActionResult> Index()
{
List<UserViewModel> allUsers = await _requestManager.GetUsers();
if(allUsers == null)
{
throw new HttpException(404, "No Users Found");
}
return View(allUsers);
}
}
Then in your unit tests you can mock IRequestManager.
public class UserControllerTest
{
[Test]
public async Task TestIndex()
{
//arrange
Mock<IRequestManager> requestManager = new Mock<IRequestManager>();
//setup what you want here...
UserController sut = new UserController(requestManager.Object);//suggest to use AutoMoqer for this.
//act
var view = await sut.Index() as ActionResult;
//assert
Assert.That(view is ViewResult);
Assert.That(view.Model is List<UserViewModel>);
}
}
Try this one..
public class UserController : Controller
{
private RequestManager requestManager = new RequestManager();
Mock<RequestManager> mockRepository = new Mock<RequestManager>();
Mock<UserViewModel> mockUserViewModel = new Mock<UserViewModel>();
ViewResult viewResult;
// GET: User
public async Task<ActionResult> Index()
{
List<UserViewModel> allUsers = await requestManager.GetUsers();
if(allUsers == null)
{
throw new HttpException(404, "No Users Found");
}
return View(allUsers);
}
}
public class UserControllerTest
{
public UserController controller;
[OneTimeSetUp]
public void InIt()
{
controller = new UserController();
}
[Test]
public async Task TestIndexWhenAllUsersNULL()
{
var view = await controller.Index() as ActionResult;
List<mockUserViewModel> listofusermodel = new List<mockUserViewModel>();
//add some dummy data in your List so it will not getting data directly from your Database
mockRepository.Setup(x => requestManager.GetUsers()).Returns(listofusermodel);
Assert.That(view is ViewResult);
Assert.That(view.Model is List<mockUserViewModel>);
}
}

MVC 6 How can I include a BaseRepository in my controller class

I am using an ORM to connect to the database it is called dapper. The issue with it is that it's database calls are synchronous and I recently found a way to make it asynchronous by following this short tutorial http://www.joesauve.com/async-dapper-and-async-sql-connection-management/ . My question is how can I bring this BaseRepository into my Controller class ? This is the code on that website and it's the same one I have
BaseRepository- by the way there is no issue in this code
public abstract class BaseRepository
{
private readonly string _ConnectionString;
protected BaseRepository(string connectionString)
{
_ConnectionString = connectionString;
}
protected async Task<T> WithConnection<T>(Func<IDbConnection, Task<T>> getData)
{
try {
using (var connection = new SqlConnection(_ConnectionString)) {
await connection.OpenAsync(); // Asynchronously open a connection to the database
return await getData(connection); // Asynchronously execute getData, which has been passed in as a Func<IDBConnection, Task<T>>
}
}
catch (TimeoutException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex);
}
catch (SqlException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex);
}
}
}
and now he brings it in like this
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
The part I am having a problem with is this public class PersonRepository : BaseRepository because Asp.Net Controllers start with public class HomeController: Controller , I need access to the WithConnection method to get this working. My controller looks like this
public class HomeController : Controller
{
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<ActionResult> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return View(topfive);
});
}
}
I obviously can not cover my ActionResult method with the BaseRepository because it gives all types of errors any suggestions ?
Why are you using inheritance instead of composition? What about something like:
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<List<TopFileClass>> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return topfive;
});
}
public class HomeController : Controller
{
private readonly PersonRepository _repo;
public HomeController(PersonRepository repo)
{
_repo = repo;
}
public async Task<ActionResult> TopFive()
{
var top5 = await _repo.topfive();
return View(top5);
}
}
If you are not familiar how to make the repository automatically get injected into the constructor, read up on dependency injection in MVC 6.
you have to intehirt the "BaseRepository" from "Controller". i think that will work for you. then just go with below code:
public abstract class BaseRepository : Controller
{
// do you work
}
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}

Asynchronous request not working after separating data retrieval code

I am trying to display some results after querying a webapi as below -
public async Task<ActionResult> Get()
{
string _address = "someurl";
string results = null;
HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));
HttpResponseMessage responseTask = await client.GetAsync(_address);
if (responseTask.IsSuccessStatusCode)
{
results = await responseTask.Content.ReadAsStringAsync();
}
ResultModel model = JsonConvert.DeserializeObject<ResultModel>(results);
return View(model);
}
This code works fine and I am able to read the results from "someurl" url. Now, when I refator the code as below (by moving the async data retrieval to another function), it stops working. It forever takes to query and does not return any result. Is this because of some deadlock or am I not using async correctly.
public ActionResult Get()
{
string _address = "someurl";
Task<string> results = HttpClientService.HttpClientService.GetRequest(_address);
IEnumerable<ResultModel> model = JsonConvert.DeserializeObject<IEnumerable<ResultModel>>(results.Result);
return View(model);
}
public static class HttpClientService
{
public static async Task<string> GetRequest(string Url)
{
HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));
HttpResponseMessage responseTask = await client.GetAsync(Url);
if (responseTask.IsSuccessStatusCode)
{
return await responseTask.Content.ReadAsStringAsync();
}
else
{
return "Sorry buddy, cannot retrieve the requested data!";
}
}
}
Please let me know what am I doing wrong here. I am new to Async implementation.
You should await the GetRequest method. Otherwise you are defeating the purpose of async processing which is to release the thread so it can do other work. In this case you are still blocking the thread when you ask for a result via results.Result.
public async Task<ActionResult> Get()
{
string _address = "someurl";
string results = await HttpClientService.HttpClientService.GetRequest(_address);
IEnumerable<ResultModel> model = JsonConvert.DeserializeObject<IEnumerable<ResultModel>>(results);
return View(model);
}
Frankly I am not sure why your code is not returning but even if it was working correctly it would be pointless to do async requests in this way.

MVC4 "Cannot await"

The following code snippet is causing a compilation error that I am hard to understand.
Error 1 Cannot await System.Collections.Generic.List'<BusinessLogic.News>'
Any suggestions?
public class NewsController : Controller
{
public async Task<ActionResult> Index(int page=1)
{
NewsNavigator News = new NewsNavigator();
await News.Load(page);
...
return View(News);
}
}
public List<News> Load(int page = DefaultPage, int pageSize = DefaultPageSize, string filter = DefaultFilter)
{
//DBLayer_News
...
return LoadedNews;
}
Await is applied to the result of a method call that returns a Task.
You cannot call it on News because News isn't a Task. Create a Task and pass your News.Load method to it.
NewsNavigator News = new NewsNavigator();
var newsLoadTask = Task.Factory.StartNew(() => News.Load(page));
await newsLoadTask;
...

Resources