I have this database call in my controller:
var addresses = db.Addresses.Where(a=>a.EmployeeId == id).ToList();
It works fine the way it is, but I am having a hard time to make it async. When I do make it async, I am able to select all records in the table or a single record, just fine. However, I can't seem to get multiple records with matching EmployeeId.
I found the solution to my own question.
var addresses = db.Addresses.Where(a=>a.EmployeeId == id).ToList();
To make the above call asynchronous I changed it to:
var addresses = await db.Addresses.Where(a=>a.EmployeeId == id).ToListAsync();
The entire method will look like following:
public async Task<ActionResult> FindAddress(int? id)
{
if(id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var addresses = await db.Addresses.Where(a=>a.EmployeeId == id).ToListAsync();
if (addresses == null)
return HttpNotFound();
return View(addresses);
}
Related
I'm just getting to grips with creating a new WebAPI2 project in ASP.NET. I'm trying to get the controller to return data from a DTO I have created rather than the raw object classes that EF created. I've been following a tutorial on Microsoft Docs and have got my method which returns all records to work using the DTO, but I can't figure out how to correctly modify the method which only returns the record with the ID matching the passed parameter using an asynchronous task, like the default method does.
The default method generated by Visual Studio looks like this:
[ResponseType(typeof(Post))]
public async Task<IHttpActionResult> GetPost(int id)
{
Post post = await db.Post.FindAsync(id);
if (post == null)
{
return NotFound();
}
return Ok(post);
}
and I've got my modified method looking like this:
[ResponseType(typeof(PostDTO))]
public async Task<IHttpActionResult> GetPost(int id)
{
var _post = from p in db.Post
where p.PostID == id
select new PostDTO()
{
PostID = p.PostID,
SubmitTime = p.SubmitTime,
SubmitUsername = p.SubmitUsername,
};
if (_post == null)
{
return NotFound();
}
return Ok(_post);
}
This methods works just fine, but as you can see, it doesn't make use of .NET's Await/Async feature to perform the query asynchronously. I'll be honest and admit that I don't actually know if this matters, but I feel like if the default method was asynchronous, so should mine be. I just can't work out where to insert the Async and Await keywords to make this work.
You can use this method as,
[ResponseType(typeof(PostDTO))]
public async Task<IHttpActionResult> GetPost(int id)
{
var _post = await (from p in db.Post
where p.PostID == id
select new PostDTO()
{
PostID = p.PostID,
SubmitTime = p.SubmitTime,
SubmitUsername = p.SubmitUsername,
}).ToListAsync();
if (_post == null)
{
return NotFound();
}
return Ok(_post);
}
In my application, i have a check, which checks the COUNT of a bunch of database tables. If each of these COUNTS is above a certain threshold, then it sets a property as active. Here is an example of a controller where a user adds room information
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "ID,RoomTypeID,Description")] Room room, int propertyId)
{
if (ModelState.IsValid)
{
room.ID = Guid.NewGuid();
room.DateCreated = DateTime.Now;
room.PropertyID = propertyId;
db.Rooms.Add(room);
await db.SaveChangesAsync();
var roomCount = db.Rooms.Where(r => r.PropertyID == propertyId).Count();
var rateCount = db.Rates.Where(r => r.PropertyID == propertyId).Count();
var imageCount = db.PropertyImage.Where(r => r.PropertyID == propertyId).Count();
if(roomCount >= 3 && rateCount >= 3 && imageCount >= 3)
{
//Set Property as ACTIVE
}
return RedirectToAction("Index");
}
The problem i have, is that i want to run this check (the 3 database COUNTS and the 'if' statement) on a whole bunch of controllers. I don't want to have to duplicate this config on every controller for every action. Also, this check may be susceptible to changing, so i'd like to update it in just one place.
How am i best to go about this? Should i be creating some sort of helper class?
Thanks
You are on the right track. You want to separate that responsibility as much as you can based on your needs, or the levels of separation already established in your application. At a minimum, I would create one class that accesses the DB, and another that contains the logic to make the "if" decision. For instance Controller -> calls Helper -> calls DBAccessor
I'm building an ASP.Net Web API application and i have the following code...
public IHttpActionResult GetCustomers() {
var customers = context.Customers.ToList();
return Ok(customers);
}
I'm using the Ok() method to return customers because i'm using an IHttpActionResult return type.
Now if i have the following method
public void DeleteCustomer(int id) {
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null) {
NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
}
Can I use NotFound() method here when the return type of my ActionMethod is void???
Void does not have a return type. So you can try to call NotFound(), but I'm not sure if this would even compile - Haven't tried. Why don't you just go with an out of the box IHttpActionResult?
public IHttpActionResult DeleteCustomer(int id)
{
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null)
{
return NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
return Ok(customerInDb);
}
Using IHttpActionResult is the more elegant version. If the id is invalid, you can just safely exit your method and tell the calling client that something went wrong. If everything went well, you're just giving the client a thumbs-up. IF you return your deleted entity or just an empty Ok() should not matter at this point.
Using void may or may not delete the entity in your data storage. The client would never know, because the server would not return any response.
I'm working on an API being developed with .net Web Api 2. I've seen many blog posts and SO questions about Web Api version 1, but answers using the changes made in version 2 seem to be scarce by comparison.
Compare these two ways of handling 'errors' in a controller ItemsController
A. Using methods that create objects from System.Web.Http.Results
// GET api/user/userID/item/itemID
[Route("{itemID:int}", Name="GetItem")]
[ResponseType(typeof(ItemDTO))]
public IHttpActionResult Get(int userID, int itemID)
{
if (userID < 0 || itemID < 0) return BadRequest("Provided user id or item id is not valid");
ItemDTO item = _repository.GetItem(itemID);
if (item == null) return NotFound();
if (item.UserID != userID) return BadRequest("Item userID does not match route userID");
return Ok<ItemDTO>(item);
}
B. Throwing exceptions that can be caught by registering a custom Global Exception Handler
// ex) in WebApiConfig.cs
// config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
public class GlobalExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
Exception exception = context.Exception;
HttpException httpException = exception as HttpException;
if (httpException != null)
{
context.Result = new SimpleErrorResult(context.Request, (HttpStatusCode)httpException.GetHttpCode(), httpException.Message);
return;
}
if (exception is RootObjectNotFoundException)
{
context.Result = new SimpleErrorResult(context.Request, HttpStatusCode.NotFound, exception.Message);
return;
}
if (exception is BadRouteParametersException || exception is RouteObjectPropertyMismatchException)
{
context.Result = new SimpleErrorResult(context.Request, HttpStatusCode.BadRequest, exception.Message);
return;
}
if (exception is BusinessRuleViolationException)
{
context.Result = new SimpleErrorResult(context.Request, (HttpStatusCode)422, exception.Message);
return;
}
context.Result = new SimpleErrorResult(context.Request, HttpStatusCode.InternalServerError, exception.Message);
}
}
GET api/user/userID/item/itemID
[Route("{itemID:int}", Name="GetItem")]
[ResponseType(typeof(ItemDTO))]
public IHttpActionResult Get(int userID, int itemID)
{
if (userID < 0 || itemID < 0)
throw new BadRouteParametersException("Provided user or item ID is not valid");
ItemDTO item = _repository.GetItem(itemID);
if (item.UserID != userID)
throw new RouteObjectPropertyMismatchException("Item userID does not match route userID");
return Ok<ItemDTO>(item);
}
Both of these seem like valid options. Since I am able to return System.Web.Http.Results objects it seems like solution A. is the best one.
But consider when in my _repository my GetItem method is implemented like so
public ItemDTO GetItem(int itemId)
{
ItemInfo itemInfo = ItemInfoProvider.GetItemInfo(itemId);
if (itemInfo == null) throw new RootObjectNotFoundException("Item not found");
ItemDTO item = _autoMapper.Map<ItemDTO>(itemInfo);
return item;
}
Here I can skip calling the autoMapper on null in GetItem and also skip checking for null in the controller.
Questions
Which way makes more sense?
Should I attempt a combination of A & B?
Should I try to keep my Controllers thin or should this type of validation & processing logic be kept there since I have access to the NotFound() and BadRequest() methods?
Should I be performing this type of logic somewhere else in the framework pipeline?
I realize my question is more architectural rather than 'how do i use this feature' but again, I haven't found too many explanations of how and when to use these different features.
From my standpoint, a global exception handler makes unit testing each action easier (read: more legible). You're now checking against a specific [expected] exception versus (essentially) comparing status codes. (404 vs. 500 vs. etc.) It also makes changes/logging of error notifications (at a global/unified level) much easier as you have a single unit of responsibility.
For instance, which unit test do you prefer to write?
[Test]
public void Id_must_not_be_less_than_zero()
{
var fooController = new FooController();
var actual = fooController.Get(-1);
Assert.IsInstanceOfType(actual, typeof(BadRequestResult));
}
[Test]
[ExpectedException(typeof(BadRouteParametersException))]
public void Id_must_not_be_less_than_zero()
{
var fooController = new FooController();
var actual = fooController.Get(-1);
}
Generally speaking, I would say this is more a preference than a hard-and-fast rule, and you should go with whatever you find to be the most maintainable and easiest to understand from both an on-boarding perspective (new eyes working on the project) and/or later maintenance by yourself.
As Brad notes, this partly comes down to preference.
Using HTTP codes is consistent with how the web works, so it's the way I lean.
The other consideration is that throwing exceptions has a cost. If you're OK with paying that cost, and take that into account in your design, it's fine to make that choice. Just be aware of it, particularly when you're using exceptions for situations that aren't really exceptional but rather are things you know you may encounter as part of normal application flow.
It's an older post, but there's an interesting discussion on the topic of exceptions and performance here:
http://blogs.msdn.com/b/ricom/archive/2006/09/14/754661.aspx
and the follow-up:
http://blogs.msdn.com/b/ricom/archive/2006/09/25/the-true-cost-of-net-exceptions-solution.aspx
I am coding a MVC 5 internet application with entity framework 6 and have a question in regards to using the await keyword when using the .Where() clause.
Here is my code that works:
public async Task<Account> GetAccount(string userName)
{
if (Session[userName] == null)
{
Account account = db.accounts.Where(a => a.userName.Equals(userName)).FirstOrDefault();
if (account == null)
{
//log out
return null;
}
Session[userName] = account;
}
return Session[userName] as Account;
}
I am wanting to use the await keyword when retrieving the Account object as follows:
Account account = await db.accounts.Where(a => a.userName.Equals(userName)).FirstOrDefault();
Can the await keyword be used when using the .Where() clause?
Thanks in advance.
There is no WhereAsync() method provided by EF (obviously because it can't potentially block, since LINQ uses deferred-execution), but since you're performing a FirstOrDefault()
you could simply use the FirstOrDefaultAsync() method:
Account account = await db.accounts.FirstOrDefaultAsync(a => a.userName.Equals(userName));
See MSDN
The await keyword can only be used on methods that return "Task...", neither .Where nor .FirstOrDefault (Which is the last method in the chain, and thus would be the one the await keyword would apply to) return Task<IEnumerable<Account>>
In theory you could write you own extension method which simply wraps around the .Where and .FirstOrDefault methods.
Also, this question isn't exactly EF specific, but rather a 'pure' C# question.
public static class ExtensionMethods
{
public static async Task<IEnumerable<T>> WhereAsync<T>(this IEnumerable<T> source, Func<T, bool> selector)
{
return await Task.Run(() => source.Where(selector));
}
}
Although that would be kind of overkill imho.
You could just wrap your entire method in a Task, so your final code would be something like:
public async Task<Account> GetAccount(string userName)
{
return await Task.Run(() =>
{
if (Session[userName] == null)
{
Account account = db.accounts.Where(a => a.userName.Equals(userName)).FirstOrDefault();
if (account == null)
{
//log out
return null;
}
Session[userName] = account;
}
return Session[userName] as Account;
});
}