I have an interface named IAuthorizationRepository with the following interface:
public interface IAuthorizationRepository
{
IQueryable<User> Users { get; }
Int32 SaveChanges();
void Detach(Object entity);
void Attach(IEntityWithKey entity);
void DeleteObject(Object entity);
void AddObject(String entitySetName, Object entity);
}
Where User is defined as follows:
public class User{
string Username { get; set; }}
And I have a TestInitialize method like this:
[TestInitialize]
public void Init()
{
_repository = new Mock<IAuthorizationRepository>();
List<User> users = new List<User>();
User user = new User();
user.Username = "test_osness";
_repository.ExpectGet(r => r.Users).Returns(users.AsQueryable());
_repository.Expect(r => r.AddObject("Users", It.IsAny<Object>()))
.Callback<User>(u => users.Add(u));
_repository.Object.AddObject("Users", user);
Console.WriteLine("Users: {0}", _repository.Object.Users.Count());
}
But when I run the test I am getting a System.Reflection.TargetParameterCountException on the line which calls _repository.Object.AddObject("Users", user). I'm new to Moq, but from what I can tell this should work. What am I doing wrong. I want to add a user object to my List when AddObject("Users" , Object) is called. So _repository.Object.Users.Count() should reflect that the correct number of users.
I'm gonna overwrite my previous answer.
This line:
_repository.Expect(r => r.AddObject("Users", It.IsAny<Object>()))
.Callback<User>(u => users.Add(u));
Is looking to call a version of .Callback() that takes a single parameter. However, your "AddObject" method that you're expecting takes two parameters. I think you need something more like this:
_repository.Expect(r => r.AddObject("Users", It.IsAny<Object>()))
.Callback((s, o) => users.Add(o as User));
Now the Callback lambda takes the same number of parameters as your expectation, so it should work.
Related
I have a series of class libraries that are used in asp.net-core middleware, and in an IHostedService.
To fetch the user context, I can inject IHttpContextAccessor to grab the HttpContext user:
public class MyLibrary
{
public MyLibrary(IHttpContextAccessor accessor)
{
// set the accessor - no problem
}
public async Task DoWorkAsync(SomeObject payload)
{
// get the user from the accessor
// do some work
}
}
To be a little more abstract, I have an IUserAccessor with an HttpUserAccessor implementation:
public class HttpUserAccessor: IUserAccessor
{
IHttpContextAccessor _httpaccessor;
public HttpUserAccessor(IHttpContextAccessor accessor)
{
_httpaccessor = accessor;
}
public string GetUser()
{
// return user from _httpaccessor
}
}
and then MyLibrary does not need an IHttpContextAccessor dependency:
public class MyLibrary
{
public MyLibrary(IUserAccessor accessor)
{
// set the accessor - no problem
}
public async Task DoWorkAsync(SomeObject payload)
{
// get the user from the accessor
// do some work
}
}
My IHostedService is popping message from a queue, where the message includes:
a user context, and
a serialized SomeObject to pass to MyLibrary.DoWorkAsync
So, something like:
public class MyHostedService : IHostedService
{
IServiceScopeProvider _serviceScopeFactory;
public MyHostedService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = servicesScopeFactory;
}
public Task StartAsync(CancellationToken cancellationToken)
{ ... }
public Task StopAsync(CancellationToken cancellationToken)
{ ... }
public async Task ExecuteAsync(CancellationToken stoppingToken)
{
foreach (var message in queue)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
// todo: tell IUserAccessor what message.User is!
var payload = // create a SomeObject from the queue message
var mylibrary = _services.GetRequiredService<MyLibrary>();
await myLibrary.DoWorkAsync(payload);
}
}
}
}
So, my question is, how does MyHostedService store message.User in such a way that a custom IUserAccessor can access it in a thread-safe manner via DI?
how does MyHostedService store message.User in such a way that a custom IUserAccessor can access it in a thread-safe manner via DI?
The thing you're looking for is AsyncLocal<T> - it's like a thread-local variable but scoped to a (possibly asynchronous) code block instead of a thread.
I tend to prefer a "provider" + "accessor" pairing for this: one type that provides the value, and a separate type that reads the value. This is logically the same thing as a React Context in the JS world, though the implementation is quite different.
One tricky thing about AsyncLocal<T> is that you need to overwrite its value on any change. In this case, that's not really a problem (no message processing will want to update the "user"), but in the general case it's important to keep in mind. I prefer storing immutable types in the AsyncLocal<T> to ensure they aren't mutated directly instead of overwriting the value. In this case, your "user" is a string, which is already immutable, so that's perfect.
First, you'll need to define the actual AsyncLocal<T> to hold the user value and define some low-level accessors. I strongly recommend using IDisposable to ensure the AsyncLocal<T> value is unset properly at the end of the scope:
public static class AsyncLocalUser
{
private static AsyncLocal<string> _local = new AsyncLocal<string>();
private static IDisposable Set(string newValue)
{
var oldValue = _local.Value;
_local.Value = newValue;
// I use Nito.Disposables; feel free to replace with another IDisposable implementation.
return Disposable.Create(() => _local.Value = oldValue);
}
private static string Get() => _local.Value;
}
Then you can define a provider:
public static class AsyncLocalUser
{
... // see above
public sealed class Provider
{
public IDisposable SetUser(string value) => Set(value);
}
}
and the accessor is similarly simple:
public static class AsyncLocalUser
{
... // see above
public sealed class Accessor : IUserAccessor
{
public string GetUser() => Get();
}
}
You'll want to set up your DI to point IUserAccessor to AsyncLocalUser.Accessor. You can also optionally add AsyncLocalUser.Provider to your DI, or you can just create it directly.
Usage would go something like this:
foreach (var message in queue)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var userProvider = new AsyncLocalUser.Provider(); // (or get it from DI)
using (userProvider.SetUser(message.User))
{
var payload = // create a SomeObject from the queue message
var mylibrary = _services.GetRequiredService<MyLibrary>();
await myLibrary.DoWorkAsync(payload);
}
}
}
This is my first Asynchronous EF attempt :)
I am having a generic entity framework repository and I want to make it async.
The original code is:
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = dbSet;
return query.ToList();
}
I trnsfor it as:
public class GenericRepository<TEntity> where TEntity : class
{
internal Context context;
internal DbSet<TEntity> dbSet;
public GenericRepository(Context context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual Task<IEnumerable<TEntity>> Get()
{
IQueryable<TEntity> query = dbSet;
return query.ToListAsync();
}
}
However, I have compile error, cannot convert type System.threading.Tasks.Task> to return type Tasks.Task>
The ToListAsync() method retrieve a list and I am expecting an Task>, my oringinal IEnumerable results is using elsewhere to populate selectbox
_xxx.Get().Select(x => new SelectListItem
{
Value = x.ps_id.ToString(),
Text = x.ps_label
}).OrderBy(x => x.Text);
Can you point me out what need to be done to do it correctly
Thanks
Task<T> is invariant because it's a class. It makes more sense to return a list since you're going through the work of making it that way anyway.
public virtual Task<List<TEntity>> Get()
{
IQueryable<TEntity> query = dbSet;
return query.ToListAsync();
}
Say you've got a model that looks like
public class UserModel
{
public string UserName { get; set; }
public DateTime? DateOfBirth { get; set; }
}
The DateOfBirth field isn't required, but could be specified. You have a Web API POST endpoint that looks like
[Route("")]
[AcceptVerbs("POST")]
public async Task<IHttpActionResult> Create(UserModel user)
{
}
And we've set the JSON serializer in start up like so,
public static void Register(HttpConfiguration config)
{
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
var settings = jsonFormatter.SerializerSettings;
settings.Converters.Add(new IsoDateTimeConverter());
settings.Error += (sender, args) => Console.WriteLine("This event is fired ok");
}
If we send some JSON to the endpoint that looks like this
{
"userName": "User1",
"dateOfBirth": "jhdgjhjfg"
}
...the error event is fired in the Serializer settings and the endpoint is called. At this point, the DateOfBirth field is null and I don't have any context that a deserialization error has occurred
Reading the JSON.Net documentation, because Handled == false in the Error event arguments of the Settings object, an exception should be raised into the application code - this doesn't happen? Is there a setting I haven't configured correctly for this?
How can I get context within the action so that I know a value was specified for a field and couldn't be deserialized? Even global behaviour would be fine, as long as I know this has happened and can return a 400.
UPDATE:
We can use a filter to check the Model state, then check the Model State errors for exceptions of type JsonReaderException. This lets you return a 400 with a list of violating fields
public class CheckJsonExceptionModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid)
{
return;
}
var fieldsInError = new List<string>();
foreach (var jsonException in
actionContext.ModelState.Keys.SelectMany(key => actionContext.ModelState[key].Errors)
.Select(error => error.Exception).OfType<JsonReaderException>())
{
Trace.TraceError(jsonException.Message);
fieldsInError.Add(jsonException.Path);
}
var apiError = new { ErrorMessages.BadRequestModel.Message, FieldsInError = new List<string>() };
foreach (var fieldError in fieldsInError)
{
apiError.FieldsInError.Add(fieldError);
}
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, apiError);
}
}
You have multiple options. But first, you are getting no exception because the WebApi handles this exception. Bad news.
Good news, you can handle it in at least two ways; use the ModelState.IsValid property - in your case it will be false. You can access them in your post-method. When you remove the invalid dateOfBirth it is true ;-)
Or you can use an ActionFilterAttribute to put it on your methods for re-use purposes.
For example:
public async Task<IHttpActionResult> Create(UserModel user) {
if (!ModelState.IsValid) {
// ModelState.Keys // Get all error-keys
}
}
I am building my first real MVC4 application and I have run into following issue.
I have a model for "User" class. Data for it are obtained through asynchronous call to webservice:
public sealed class AdminDMSEntities
{
public List<User> UserList { get; private set; }
public AdminDMSEntities()
{
this.UserList = new List<User>(0);
ServiceClient client = new ServiceClient();
client.GetUsersCompleted += (s, e) =>
{
if (e.Result == null)
throw new ArgumentNullException("No users were retrieved");
UserList = new List<User>(0);
e.Result.ForEach(w => this.UserList.Add(new User(w.Guid, w.TrusteeType, w.Username, w.Email, w.LastLogin, w.PasswordChanged, w.IsUsingTempPassword)));
};
client.GetUsersAsync();
}
}
I intend to use this class as I would use class derived from DbContext (if I could use Entity Framework which I cant). So far I have only users in the class.
I am using tis class in UsersController like this:
public class UsersController : Controller
{
private AdminDMSEntities adminEntities = new AdminDMSEntities();
//
// GET: /User/
public ActionResult Index()
{
return View(adminEntities.UserList);
}
}
The problem is that I will end up with InvalidOperationException, because controller is not waiting for async call completion and passes UserList to the view before it is properly filled with users.
I can have the call synchronous for the time being, but it is very likely I will be forced to use asynchronous calls later, so I would like to know how to ensure, that controller will wait for async call to be completed before UserList is passed to view...
Thanks in advance
EDIT: I have tried the approach with AsyncController as listed below, currently I have added this to AdminDMS entities class:
public static async Task<AdminDMSEntities> AdminDMSEntitiesAsync()
{
AdminDMSEntities result = null;
Task<AdminDMSEntities> getUsersAsyncTask = Task.Factory.StartNew(() => new AdminDMSEntities());
await getUsersAsyncTask;
return result;
}
and this is the change to the controller:
public class UsersController : AsyncController
{
private AdminDMSEntities adminEntities = null;
//
// GET: /User/
public async Task<ActionResult> Index()
{
if (adminEntities == null)
{
adminEntities = await AdminDMSEntities.AdminDMSEntitiesAsync();
}
return View(adminEntities.UserList);
}
}
The result is that adminEntities are containing an instance of the class, but there are no users in the list (there should be 11).
EDIT2: Since i was told that creating new task is not the right thing to do, I went with the first suggested approach removin AdminDMSEntities class from the code. My thanks to Darin for helping me out :)
You could use an asynchronous controller. The idea is to have your controller derive from the AsyncController class instead of the Controller class. This class provides methods that allow you to perform asynchronous operations.
For example:
public class MyController: AsyncController
{
public void IndexAsync()
{
AsyncManager.OutstandingOperations.Increment();
var client = new SomeClient();
client.GetUsersCompleted += (s, e) =>
{
UserList = new List<User>();
AsyncManager.Parameters["users"] = e.Result.Select(
w => new User(
w.Guid,
w.TrusteeType,
w.Username,
w.Email,
w.LastLogin,
w.PasswordChanged,
w.IsUsingTempPassword
)
)
.ToList();
AsyncManager.OutstandingOperations.Decrement();
};
client.GetUsersAsync();
}
public ActionResult IndexCompleted(IEnumerable<User> users)
{
return View(users);
}
}
and if you are using .NET 4.5 you could even take advantage of the new async keyword simplifying the asynchronous code even further. This is possible if you refactor your data access layer to the new pattern (i.e. return Tasks):
public class MyController: AsyncController
{
public async Task<ActionResult> Index()
{
var client = new SomeClient();
var users = await client.GetUsersAsync().Select(
w => new User(
w.Guid,
w.TrusteeType,
w.Username,
w.Email,
w.LastLogin,
w.PasswordChanged,
w.IsUsingTempPassword
)
)
.ToList();
return View(users);
}
}
I'm new to Mocking, but this must be something really basic that I'm missing:
The test code below produces an exception:
Expected invocation on the mock at least once, but was never performed: x => x.DeleteProducts(._products)\r\n\r\nConfigured setups:\r\nx => x.DeleteProducts(._products), Times.Never\r\n\r\nPerformed invocations:\r\nIProductRepository.DeleteProducts(System.Collections.Generic.List`1[WebApiDemo.DataAccessLayer.Product])
I step through the controller method and it does seem to call the DeleteProducts method...
// Arrange
IEnumerable<Product> _products = Helpers.ProductHelpers.CreateProducts(_numberProducts);
Mock<IProductRepository> _productRepository = new Mock<IProductRepository>();
_productRepository.Setup(x => x.DeleteProducts(_products));
ProductsController controller = new ProductsController(_productRepository.Object);
// Act
controller.Destroy(_productViewModels); // Destroy calls DeleteProducts
// Assert
_productRepository.Verify(x => x.DeleteProducts(_products));
Does DeleteProducts(_products); return void? I assume it does, so you need to put the .Verifiable() at the end of the .Setup() for it.
With that in place, it should run through ok, although I'm not sure why you have the Times.Never() instead of Times.Once() ??
I would also advocate on the Setup call using It.IsAny<T> rather than a specific collection, such as:
MyMock.Setup(x => x.MyMethod(It.IsAny<IEnumerable<Widget>>)).Verifiable()
Unless you have the mock behaviour set to strict there is no need for the setup. You are not returning anything from the Delete. The call to Verify will suffice.
Some things are not totally obvious from the code.
The repository deletes products but the controller destroys productviewmodels.
In Moq 4 the test should work if
You have a product view model for every product in _products
The Controller.Destroy method gets products from the viewmodels in the same order as _products
I would check that _productViewModels is a 1:1 match to the _products and check how Destroy() extracts the products from the viewmodels before calling Delete()
I would not go with the IsAny>() because you want to check that these specific products were deleted not any other ones.
[TestClass]
public class Verifying {
public interface IProductRepository {
void Delete(IEnumerable<Product> products);
}
public class ProductController {
private IProductRepository _repository;
public ProductController(IProductRepository repository) {
_repository = repository;
}
public void Destroy(IEnumerable<Product> products) {
_repository.Delete(products);
}
public void Destroy(IEnumerable<ProductViewModel> productViewModels) {
_repository.Delete(productViewModels.Select(vm => vm.Product));
}
}
public class Product {
}
public class ProductViewModel {
public Product Product { get; set;}
}
static Verifying() {
sProducts = new List<Product> { new Product(), new Product(), new Product() };
sProductViewModels = new List<ProductViewModel>(sProducts.Select(p => new ProductViewModel { Product = p }));
}
private static List<Product> sProducts;
private static List<ProductViewModel> sProductViewModels;
private Mock<IProductRepository> _mockRepository;
private ProductController CreateController() {
_mockRepository = new Mock<IProductRepository>();
return new ProductController(_mockRepository.Object);
}
[TestMethod]
public void DestroyingProducts() {
var controller = CreateController();
controller.Destroy(sProducts);
_mockRepository.Verify(mk => mk.Delete(sProducts));
}
[TestMethod]
public void DestroyingProductViewModels() {
var controller = CreateController();
controller.Destroy(sProductViewModels);
_mockRepository.Verify(mk => mk.Delete(sProducts));
}
}