How to use Await with LINQ and DTO - asp.net

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);
}

Related

Convert an api result set to a c# Object

I am calling an API to get a set of assignment data as JSON. I would like to convert that into C# model objects and display the results in my MVC view. Here is my code so far that successfully brings back the results, now I need it converted to an assignment Model (i.e I need API response.content turned into assignment).
[HttpGet]
public async Task<ViewResult> Index()
{
if (!ModelState.IsValid)
{
return View("Error");
}
HttpRequestMessage apiRequest = CreateRequestToService(HttpMethod.Get, "api/Assignment/GetAll");
HttpResponseMessage apiResponse;
Assignment assignment = new Assignment();
try
{
apiResponse = await HttpClient.SendAsync(apiRequest);
}
catch
{
return View("Error");
}
if (!apiResponse.IsSuccessStatusCode)
{
return View("Error");
}
var result = apiResponse.Content.ReadAsStringAsync();
var results = ???
return View( results);
}
I need API response.content turned into assignment
Convert the content of the response to the desired type. Lets assume it is a collection of the models
//...
var assignments = await apiResponse.Content.ReadAsAsync<List<Assignment>>();
//...

ASP.NET Web Api - "PATCH" using Delta<...> with double property not working

From JavaScript client code I am creating the following data:
var employee = {
FirstName: "Rudolf",
Salary: 99
};
I then pass this through an Ajax call to an MVC Web API Controller Action:
using System.Web.Http.OData;
public async Task<IHttpActionResult> Patch([FromUri] int employeeId, [FromBody] Delta<Employee> employee)
{
await _employeeService.Patch(employeeId, employee);
return Ok();
}
This calls my service to update the database as follows:
public async Task Patch(int employeeId, Delta<Employee> employee)
{
using (var context = new DBEntities())
{
if (employee.TryGetPropertyValue("Salary", out object salary))
{
var ss = Convert.ToDouble(salary); // Always 0
}
if (employee.TryGetPropertyValue("FirstName", out object firstName))
{
var ss = Convert.ToString(firstName); // Expected value
}
var currentEmployee = await context.Employees
.FirstOrDefaultAsync(e => e.Id == employeeId);
if (currentEmployee == null)
return;
employee.Patch(currentEmployee);
await context.SaveChangesAsync();
}
}
Note: I missed out some of the details for brevity as the actual client-server call is working fine.
The code seems to work as expected, but the Salary property (the only none-string one) is always set to 0 (zero). So that field never get's updated.
Any ideas why the Salary is not being passed through?
Note: I use very similar client-server code for GET/POST/PUT/DELETE and they all work fine, so I believe it is related to the Delta<> part.
Yes, I encountered the same problem with int properties.
I solved the problem using SimplePatch (v1.0 is only 10KB).
Disclaimer: I'm the author of the project.
It is inspired to Microsoft.AspNet.WebApi.OData but SimplePatch has no dependencies.
How to use
Install the package using:
Install-Package SimplePatch
Your MVC Web API Controller Action becomes:
using SimplePatch;
public async Task<IHttpActionResult> Patch([FromUri] int employeeId, [FromBody] Delta<Employee> employee)
{
await _employeeService.Patch(employeeId, employee);
return Ok();
}
Then your Patch method becomes:
public async Task Patch(int employeeId, Delta<Employee> employee)
{
using (var context = new DBEntities())
{
if (employee.TryGetPropertyValue("Salary", out object salary))
{
var ss = Convert.ToDouble(salary);
}
if (employee.TryGetPropertyValue("FirstName", out object firstName))
{
var ss = Convert.ToString(firstName);
}
var currentEmployee = await context.Employees
.FirstOrDefaultAsync(e => e.Id == employeeId);
if (currentEmployee == null)
return;
employee.Patch(currentEmployee);
await context.SaveChangesAsync();
}
}
Also, SimplePatch gives you the ability to ignore some properties when calling the Patch method.
Global.asax or Startup.cs
DeltaConfig.Init((cfg) =>
{
cfg.ExcludeProperties<Employee>(x => x.YourPropertyName);
});
If Salary has type int then there is an issue with that type
The Json parser converts integers to 64 bit ones, which won't match the 32 bit int properties declared on the entity and thus get ignored by this method.
This problem is mentioned here
So, you can use long instead of int or using the OData media type formatters
See this

ASP.Net Web API Action Result

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.

EF6 - Using the await keyword with the Where() clause

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;
});
}

How can I do an async fetch of all the data from an entity with EF6.1?

I am using WebAPI and I tried to scaffold a controller. This is the method it came up with for a fetch by ID:
// GET: api/ExamStatus/5
[ResponseType(typeof(ExamStatus))]
public async Task<IHttpActionResult> GetExamStatus(int id)
{
ExamStatus examStatus = await db.ExamStatus.FindAsync(id);
if (examStatus == null)
{
return NotFound();
}
return Ok(examStatus);
}
What if I wanted to do an async select of all the data from the ExamStatus entity? Can someone explain how I can do this?
You could try the .ToListAsync extension method:
[ResponseType(typeof(List<ExamStatus>))]
public async Task<IHttpActionResult> GetExamStatuses()
{
var result = await db.ExamStatus.ToListAsync();
return Ok(result);
}
Obviously this will select ALL the rows in your database and serialize them into the response.

Resources