I think Breezejs is a great tool but wonder if we can integrate EF and breeze further.
Specifically, can we use async methods and return List<T> instead of IQueryable?
For example:
public async Task<object> Lookups()
{
var countries = await _repository.Countries.ToListAsync();
var states = await _repository.States.ToListAsync();
var parent = await _repository.Parent.Include(p => p.Children)
.Include(p => p.Children.Address)
return new { countries, states, locations, parent};
}
This works for simple objects like countries and states, but when the queries are more complicated, for example Parent-Child-Address, the Address disappears once in the client side.
It would be great to tap on all the async model while keeping all the Breeze features.
Totally agree.
We have it on our backlog to offer Web API helper components that support the async model. Please add your vote to this User Voice topic.
Related
All my repository methods are async for my CRUD operations using EF.Core async methods and use AutoMapper to map my EF entity model (Customer) to Domain Model (CustomerModel) and pass it back to my service layer.
public async Task<CustomerModel> GetCustomerByIdAsync(int id)
{
Customer customer = await _context.Customers.FindAsync(id);
var mappedResult = _mapper.Map<CustomerModel>(customer);
return await Task.FromResult(mappedResult);
}
Since "_mapper.Map" is not async but GetCustomerByIdAsync is, I return await Task.FromResult(mappedResult) instead of return mappedResult;
My caller method in service layer is also async. Have I got this right? I am also wondering about deadlock implications, although I am not calling any of my async methods from sync methods using .Result.
Thanks for your time.
Since "_mapper.Map" is not async but GetCustomerByIdAsync is, I return await Task.FromResult(mappedResult) instead of return mappedResult;
No, await Task.FromResult(x) doesn't ever make any sense. I've seen this code a lot, and I'm not sure where it comes from.
await Task.FromResult(x) is literally a less-efficient way of writing x. It's less efficient and less maintainable, so I have no idea where this idea came from.
Your code should look like:
public async Task<CustomerModel> GetCustomerByIdAsync(int id)
{
Customer customer = await _context.Customers.FindAsync(id);
var mappedResult = _mapper.Map<CustomerModel>(customer);
return mappedResult;
}
We are trying to use RunImpersonated(handle, action); to be able to perform a REST call from a webserver but we have a hard time doing so. Project i ASP.NET Core 2.0 MVC.
We have the following general method made to establish a imp. context on behalf of the logged in wnd. user:
var user = WindowsIdentity.GetCurrent();
IntPtr token = user.Token;
SafeAccessTokenHandle handle = new SafeAccessTokenHandle(token);
WindowsIdentity.RunImpersonated(handle, action);
and basically in the action we make our REST call.
Thing is that we CAN run through without any problems running locally on our dev machines but we can't do the same on the remote webserver. Hence: impersonation.
Is our approach above for the imp. part right since we can't actually se if we promote any user-credentials?
We have tried different techniques in the REST-GET impl. as well without the above. On the other hand the above call are made closer to our controller and on REST impl. not having any specifics for imp. itself.
I was concerned with some time ago. As far as I can remmember, this worked for me:
Create an asynchronous action filter:
public class ImpersonationFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
var user = (WindowsIdentity)context.HttpContext.User.Identity;
await WindowsIdentity.RunImpersonated(user.AccessToken, async () =>
{
await next();
});
}
}
Register it as any other filter.
I found an interesting differences between .NET Framework's HttpClient class/objects and the VS-2013 Project PhotoServer (DLL) class/objects. It made me wonder if there's a bug with the script.
I'm using .NET Framework v4.5.1.
I'm using the HttpClient script in the sychronous Web Generic Handler. Noticed that I'm using the ".Result" for the asynchronous POST to wait for response. So, looking at HttpClient which works is
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(
_baseUrl,
new FormUrlEncodedContent
(
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Vin", parmVin),
new KeyValuePair<string, string>("ImageSize", parmImageSize)
}.ToArray()
)
).Result;
//returned string[] datatype...
var photoUrls = response.Content.ReadAsStringAsync().Result;
}
I'm using the "GetPhotoUrlsAsync" script in the sychronous Web Generic Handler. This "GetPhotoUrlsAsync" object comes from the Project class (DLL). Again, I'm using the ".Result" and it doesn't work, it just deadlocked and hung. What I wanna know is why is that and was there a bug with the script?
//[Scripts in Web Generic Handlers]...
var managerVehiclePhoto = new ManagerVehiclePhoto();
var photoUrls = managerVehiclePhoto.GetPhotoUrlsAsync("12345678901234567").Result;
//[Project Class]...
namespace BIO.Dealer.Integration.PhotoServer
{
public seal class VehiclePhotoManager
{
public async Task<string[]> GetPhotoUrlsAsync(string vin)
{
var listResponse = await _client.ListAsync(vin);
return listResponse.ToArray();
}
}
}
Thanks...
Edit #1
//Synchronous API Call...
public string[] GetPhotoUrls(string vin)
{
return GetPhotoUrlsAsync(vin).Result;
}
Using .Result like this is actually a bug in both cases; it just happens not to deadlock in the HttpClient case. Note that the same HttpClient library on other platforms (notably Windows Phone, IIRC) will deadlock if used like this.
I describe the deadlock in detail on my blog, but the gist of it is this:
There's an ASP.NET "request context" that is captured by default every time you use await. When the async method resumes, it will resume within that context. However, types such as HttpContext are not multithread-safe, so ASP.NET restricts that context to one thread at a time. So if you block a thread by calling .Result, it's blocking a thread inside that context.
The reason GetPhotoUrlsAsync deadlocks is because it's an async method that is attempting to resume inside that context, but there is already a thread blocked in that context. The reason HttpClient happens to work is because GetAsync etc. are not actually async methods (note that this is an implementation detail and you should not depend on this behavior).
The best way to fix this is to replace .Result with await:
var managerVehiclePhoto = new ManagerVehiclePhoto();
var photoUrls = await managerVehiclePhoto.GetPhotoUrlsAsync("12345678901234567");
Me again (re: same quest WebPages async) :) That said, I'm one of those that Stephen Cleary identifies as "trying to migrate into async", so all this is (still) a learning moment.
The issue is SynchronizationContext in GUI/ASP.Net. I won't mangle Stephen's explanation so the link is your best bet to grok.
Given the best practices in that article, here's my way (consequently what I use in WebPages for the "top level call") to "mock" awaiting a PostAsync call like what you're doing. In this case I'm using ConfigureAwait (call is from WebPages, not MVC):
public static async Task<string> PostToRequestBin()
{
var _strContent = new FormUrlEncodedContent(new[] {new KeyValuePair<string,string>("fizz","buzz")});
using (var client = new HttpClient())
{
/*
* See http://requestb.in/ for usage
*/
var result = await client.PostAsync("http://requestb.in/xyzblah", _strContent).ConfigureAwait(false);
return await result.Content.ReadAsStringAsync();
}
}
In my WebPages page:
#{
//Class2 is a mock "library" in App_Code where the above async code lives
var postcatcher = Class2.PostToRequestBin();
}
And to make use of it somewhere in the page (where I make use of Task<string>.Result:
<p>#postcatcher.Result</p>
Again, this is a learning moment and I hope it helps/guides you. I fully expect the SO community to comment and or correct/improve on this like:
"Why don't I have to ConfigureAwait on ReadAsStringAsync" (it works either way)?
because at this point, it's "async all the way". I could have awaited some other async method...
...so the learning moments continue :)
I've been working on coming with a SignalR Unit testing framework using Moq.
I have been able things to get reasonably well with the 1 group - 1 client (connection) scenario.
How do I set up Moq so I can:
1) Add/remove multiple clients from the same group?
2) Add/remove multiple groups on the same mocked hub?
I'm relatively new to the world of Moq and SignalR combination.
Thanks in advance,
JohnB
Here is an example testing adding a client to multipe groups using Moq and xUnit.net:
[Fact]
public async Task MyHubAddsConnectionToTheCorrectGroups()
{
// Arrange
var groupManagerMock = new Mock<IGroupManager>();
var connectionId = Guid.NewGuid().ToString();
var groupsJoined = new List<string>();
groupManagerMock.Setup(g => g.Add(connectionId, It.IsAny<string>()))
.Returns(Task.FromResult<object>(null))
.Callback<string, string>((cid, groupToJoin) =>
groupsJoined.Add(groupToJoin));
var myHub = new MyHub();
myHub.Groups = groupManagerMock.Object;
myHub.Context = new HubCallerContext(request: null,
connectionId: connectionId);
// Act
await myHub.AddToGroups();
// Assert
groupManagerMock.VerifyAll();
Assert.Equal(3, groupsJoined.Count);
Assert.Contains("group1", groupsJoined);
Assert.Contains("group2", groupsJoined);
Assert.Contains("group3", groupsJoined);
}
public class MyHub : Hub
{
public async Task AddToGroups()
{
await Groups.Add(Context.ConnectionId, "group1");
await Groups.Add(Context.ConnectionId, "group2");
await Groups.Add(Context.ConnectionId, "group3");
}
}
The basic idea is to define a Callback along with your Setup that stores arguments important to your test inside a collection. You can then use the collection verify that the method you mocked was called the right number of times with the right arguments. I don't verify the order of the calls to Groups.Add in my example test, but you can test that as well.
This pattern extends pretty trivially to testing the adding/removing of multiple clients. Basically, you would just need a second collection to store the connectionId arguments passed to Groups.Add.
I have been experimenting with a lightweight solution for handling my business logic. It consists of a vanilla ADO.NET connection that is extended with Dapper, and monitored by Glimpse.ADO. The use case for this setup will be a web application that has to process a handful of queries asynchronously per request. Below a simple implementation of my setup in an MVC controller.
public class CatsAndDogsController : Controller
{
public async Task<ActionResult> Index()
{
var fetchCatsTask = FetchCats(42);
var fetchDogsTask = FetchDogs(true);
await Task.WhenAll(fetchCatsTask, fetchDogsTask);
ViewBag.Cats = fetchCatsTask.Result;
ViewBag.Dogs = fetchDogsTask.Result;
return View();
}
public async Task<IEnumerable<Cat>> FetchCats(int breedId)
{
IEnumerable<Cat> result = null;
using (var connection = CreateAdoConnection())
{
await connection.OpenAsync();
result = await connection.QueryAsync<Cat>("SELECT * FROM Cat WHERE BreedId = #bid;", new { bid = breedId });
connection.Close();
}
return result;
}
public async Task<IEnumerable<Dog>> FetchDogs(bool isMale)
{
IEnumerable<Dog> result = null;
using (var connection = CreateAdoConnection())
{
await connection.OpenAsync();
result = await connection.QueryAsync<Dog>("SELECT * FROM Dog WHERE IsMale = #im;", new { im = isMale });
connection.Close();
}
return result;
}
public System.Data.Common.DbConnection CreateAdoConnection()
{
var sqlClientProviderFactory = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
var dbConnection = sqlClientProviderFactory.CreateConnection();
dbConnection.ConnectionString = "SomeConnectionStringToAwesomeData";
return dbConnection;
}
}
I have some questions concerning the creation of the connection in the CreateAdoConnection() method. I assume the following is happening behind the scenes.
The call to sqlClientProviderFactory.CreateConnection() returns an instance of System.Data.SqlClient.SqlConnection passed as a System.Data.Common.DbConnection. At this point Glimpse.ADO.AlternateType.GlimpseDbProviderFactory kicks in and wraps this connection in an instance of Glimpse.Ado.AlternateType.GlimpseDbConnection, which is also passed as a System.Data.Common.DbConnection. Finally, this connection is indirectly extended by the Dapper library with its query methods, among them the QueryAsync<>() method used to fetch the cats and dogs.
The questions:
Is the above assumption correct?
If I use Dapper's async methods with this connection - or create a System.Data.Common.DbCommand with this connection's CreateCommand() method, and use it's async methods - will those calls internally always end up using the vanilla async implementations of these methods as Microsoft has written them for System.Data.SqlClient.SqlConnection and System.Data.SqlClient.SqlCommand? And not some other implementations of these methods that are actually blocking?
How much perf do I lose with this setup compared to just returning a new System.Data.SqlClient.SqlConnection directly? (So, without the Glimpse.ADO wrapper)
Any suggestions on improving this setup?
Yes pretty much. GlimpseDbProviderFactory wraps/decorates/proxies all the registered factories. We then pass any calls we get through to the factory we wrap (in this case SQL Server). In the case of CreateConnection() we ask the inner factory we have, to create a connection, when we get that connection, we wrap it and then return it to the originating caller
Yes. Glimpse doesn't turn what was an async request into a blocking request. We persevere the async chain all the way though. If you are interested, the code in question is here.
Very little. In essence, using a decorator pattern like this adds only one or two frames to the call stack. Compared to most operations performed during the request lifecycle, the time to observe whats happening here is extremely minimal.
What you have looks great. Only suggestion is to maybe us this code to build the factory. This code means that you can shift your connection string, etc to the web.config.