Automapper Queryable Extensions not appearing - iqueryable

I am using the following:
EntityFrameworkCore 3.1.2
.Net Standard Library 2.1
Automapper 9.0.0
Automapper.Extension.Microsoft.DependencyInjection 7.0.0
My DI for AutoMapper looks like this:
services.AddAutoMapper(Assembly.GetExecutingAssembly());
I have an IMapFrom with default implementation:
using AutoMapper;
namespace Application.Common.Mappings
{
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
}
I have a DTO class as follows:
public class ServiceRegistrationDto : IMapFrom<ServiceRegistration>
{
public string ServiceName { get; set; }
public string MessageType { get; set; }
public string ServiceURL { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<ServiceRegistration, ServiceRegistrationDto>();
}
}
In my Handler I am doing the following:
public async Task<ServiceRegistrationViewModel> Handle(GetServiceRegistrationListQuery request, CancellationToken cancellationToken)
{
var serviceRegistrations = await _context.ServiceRegistrations
.Where(s => s.MessageType.Equals(request.MessageType, StringComparison.InvariantCultureIgnoreCase))
.ProjectTo<ServiceRegistrationDto>(_mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
return null;
}
The issue is that the "ProjectTo" is not a definition of IQueryable. I was under the impression that Automapper had Queryable Extensions. Am I missing a NuGet Package? I am following examples from Northwind Traders and I can't figure out what I have different.
I can get to "ProjectTo" using IMapper like this:
var x = _mapper.ProjectTo<ServiceRegistrationDto>(serviceRegistrations);
But I would prefer to do it as part of the IQueryable like you should be able to.

I took a step back from the code and realized I was missing the
using AutoMapper.QueryableExtensions;
DOH!!!

Related

How to inject a service into a constructor when creating a new instance of an object?

The Setup: I've registered a configuration service that pulls data from appsettings.json and it works fine. I also have a controller that uses that service to get settings from that file, again this works like it's supposed to:
public class ApiController : Controller
{
private readonly string _apiUri;
public ApiController(IOptions<Configurator> config)
{
_apiUri = config.Value.ApiSettings.ApiBaseUrl +
config.Value.ApiSettings.ApiVersion;
}
//...
}
Now note, I'm new to automated unit testing and to asp.net core. What I'd like to do is to decouple the ApiController's reliance on the injected service so that I can use a separate XUnit test project to test functions inside the controller, similar to the example in this tutorial.
To do this I created a model and interface representing the ApiSettings section of my appsettings.json file:
"ApiSettings": {
"ApiBaseUrl": "https://example.com/api/",
"ApiVersion": "v1/"
}
The Model:
public class ApiSettings : IApiSettings
{
public string ApiBaseUri { get; set; }
public string ApiVersion { get; set; }
}
The Interface:
public interface IApiSettings
{
string ApiBaseUri { get; set; }
string ApiVersion { get; set; }
}
I then created a class that would be dependent on the service to inject the settings:
public class ApiSettingsBuilder
{
private readonly string _apiUri;
public ApiSettingsBuilder(IOptions<Configurator> config)
{
_apiUri = config.Value.ApiSettings.ApiBaseUrl +
config.Value.ApiSettings.ApiVersion;
}
public string ApiUri { get { return _apiUri; } }
}
The Problem: How do I create an new instance of this class?
public class ApiController : Controller
{
private readonly string _apiUri;
public ApiController()
{
ApiSettingsBuilder builder = new ApiSettingsBuilder(/*What do I do here*/);
_apiUri = builder.ApiUri;
}
public ApiController(IApiSettings settings)
{
//For testing
_apiUri = settings.ApiBaseUrl + settings.ApiVersion;
}
//...
}
Also, I know this is all a bit overkill, but I would still like an answer because It would possibly be useful in other scenarios.
You don't have to create new classes for unit testing purposes, you can mock the interface of your IOptions using appropriate framework, e.g. Moq:
var configurator = new Configurator() { ApiBaseUrl = "abc" };
var mock = new Mock<IOptions<Configurator>>();
mock.Setup(ap => ap.Value).Returns(configurator);
Then you can pass mocked object to your constructor for unit testing:
var controller = new ApiController(mock.Object);

C# Entity Framework Core & Repository

Having some issues getting my repository to retrieve information - keeps coming back null. Any Thoughts would be appreciated - new to this and teaching myself.
Repository:
public class CustomerRepository : ICustomerRepository
{
private masterContext context;
public CustomerRepository(masterContext context)
{
this.context = context;
}
public IEnumerable<Customer> GetCustomers()
{
return context.Customer.ToList();
}
public Customer GetCustomerById(int customerId)
{
var result = (from c in context.Customer where c.CustomerId == customerId select c).FirstOrDefault();
return result;
}
public void Save()
{
context.SaveChanges();
}
Controller:
public class CustomerController : Controller
{
private readonly ICustomerRepository _repository = null;
public ActionResult Index()
{
var model = (List<Customer>)_repository.GetCustomers();
return View(model);
}
public ActionResult New()
{
return View();
}
}
MasterContext which i had efc make:
public partial class masterContext : DbContext
{
public masterContext(DbContextOptions<masterContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.Property(e => e.CustomerName).IsRequired();
});
}
public virtual DbSet<Customer> Customer { get; set; }
public virtual DbSet<Order> Order { get; set; }
}
I think you need to create instances of you Context and your Repository. So in your Controller you need to something like this:
private masterContext context = new masterContext();
private ICustomerRepository repository = new CustomerRepository(context);
I assume that you're not using Dependency injection ... if so you just need to create a Constructor for your Controller that takes CustomerRepository as argument:
public CustomerController(ICustomerRepository _repository) {
repository = _repository;
}
If you did not configure your database context, look here: https://docs.efproject.net/en/latest/platforms/aspnetcore/new-db.html
This will than enable you the dependency injection. Everything you than need to do for the Repository is to use
services.AddScoped<ICustomerRepository,
CustomerRepository>();
And I think it could be good to remove the ToList() in the Repository class and remove the Cast List<Customer> in your Controller and use ToList() instead, if it's really needed. Because if you're using it in the View the ienumerable could also work.

Unit testing mvc model with HttpContext.Current.User.Identity.GetUserId()

In my MVC5 application, I have a Log entity, that is used to log any call to any controler. This log uses: HttpContext.Current.User.Identity.GetUserId() to determine the identity of the user accessing the controller.
public class Log
{
public Log()
{
TS = DateTime.Now;
UserId = HttpContext.Current.User.Identity.GetUserId();
}
[Required]
public Int32 Id { get; set; }
public string UserId { get; set; }
[Display(Name = "TS", ResourceType = typeof(Resources.Models.Log.Log))]
[Required(ErrorMessageResourceType = typeof(Resources.Models.Log.Log), ErrorMessageResourceName = "RequiredTS")]
public DateTime TS { get; set; }
[Required]
public short LogTypeId { get; set; }
[Display(Name = "LogText", ResourceType = typeof(Resources.Models.Log.Log))]
public string LogText { get; set; }
public ApplicationUser User { get; set; }
}
When I try to unit test a controller and crating an instance of the log class I get this error:
threw exception: System.NullReferenceException: Object reference not
set to an instance of an object.
at DASU.Core.Models.Log..ctor()
I know this is because the context is not set.
So my question is how do I set the context, or how do I mock the context, so I can create the Log for my test?
You should avoid coupling to HttpContext. Like suggested in the comments you could simplify your log my injecting the UserId into the dependent Log class
public class Log
{
public Log(string userId)
{
TS = DateTime.Now;
UserId = userId;
}
//...other code removed for brevity
}
or abstracting away the calls to HttpContext so that you can mock your abstract and inject that instead of trying and mock HttpContext
public interface IUserProvider {
string GetUserId();
}
You production implementations can wrap calls to HttpContext and you can easily create mock implementations for your unit tests.
public class Log
{
public Log(IUserProvider userProvider)
{
TS = DateTime.Now;
UserId = userProvider.GetUserId();
}
//...other code removed for brevity
}

Cannot mock .... The profiler must be enabled to mock, arrange or execute the specified target

I have the following in a test (my first ever JustMock test, I might add)...
var template = Mock.Create<MessageType>();
Mock.Arrange(() => template.Subject)
.Returns("This template has Zero tokens.");
Mock.Arrange(() => template.Body)
.Returns("This template has {{number}} of {{tokens}}.");
The class being Mocked looks like this ...
public class MessageType : BaseBusinessEntity
{
public string Body { get; set; }
public int DigestsToBeIncludedOn { get; set; }
public Guid MessageReference { get; set; }
public int MessageTypeId { get; set; }
public string Name { get; set; }
public int PredefinedRecipients { get; set; }
public string Subject { get; set; }
}
When I attempt to run the test I get ...
Error Message: Test method
Genesis.Service.Implementation.Tests.DigestFixture.ShouldCorrectlyExtractTemplateTokens
threw exception: Telerik.JustMock.Core.ElevatedMockingException:
Cannot mock 'System.String get_Subject()'. The profiler must be
enabled to mock, arrange or execute the specified target. Stacktrace:
at
Telerik.JustMock.Core.ProfilerInterceptor.ThrowElevatedMockingException(MemberInfo
member) at
Telerik.JustMock.Core.MocksRepository.CheckMethodInterceptorAvailable(IMatcher
instanceMatcher, MethodBase method) at
Telerik.JustMock.Core.MocksRepository.AddArrange(IMethodMock
methodMock) at
Telerik.JustMock.Core.MocksRepository.Arrange[TMethodMock](Expression
expr, Func1 methodMockFactory) at
Telerik.JustMock.Mock.<>c__DisplayClass81.b__6() at
Telerik.JustMock.Core.ProfilerInterceptor.GuardInternal[T](Func1
guardedAction) at Telerik.JustMock.Mock.Arrange[TResult](Expression1
expression) at
Genesis.Service.Implementation.Tests.DigestFixture.ShouldCorrectlyExtractTemplateTokens()
in
c:\Genesis\Development\Genesis.Service.Implementation.Tests\DigestFixture.cs:line
46
Can anyone point out what I've done wrong?
Be sure you have enabled the profiler from the menu.
While using Visual Studio for writing your tests you will notice the Telerik menu and the JustMock menu-item in it. Once there, you have to check if JustMock is enabled(“Enable JustMock” should be grey, see the example bellow).

Mapping the 'count' on child list property in AutoMapper

I am working in an ASP.NET MVC 4 application, and have something similar to this for my domain.
public class Party
{
public Cake PartyCake { get; set; }
public List<Candles> CakeCandles { get; set; }
}
I want to map that to the PartyVM which looks like so:
public class PartyVM
{
public string PartyCakeName { get; set; }
public int CandlesCount { get; set; }
}
How can I tell AutoMapper to work out the Count of the list when doing its mappings? I have this, but all this does is tell it to ignore!
Mapper.CreateMap<Party, PartyVM>()
.ForMember(dest => dest.CandlesCount, opt => opt.Ignore());
Thanks.
AutoMapper supports Count out of the box, your destination member is just named incorrectly. If you name your PartyVM property "CakeCandlesCount" it will have the right value.