ASP.Net Core 2.1 OData Parameter issue - asp.net-core

I am trying to get OData to work in ASP.Net 2.1. The main Get is ok as I get the results from the DB.
When I try to call the second Get with a Parameter it returns with a 404. I put a breakpoint on the second get and it never hits. The http "get" statement http://localhost:5000/odata/userrole('Admin')
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/odata/userrole('Admin')
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 423.7117ms 404
What am I not doing right here? Thank you.
Microsoft.AspNetCore.Odata = v7.1.0
namespace MyApp.Controllers
{
public class UserRoleController : ODataController
{
private IMyDB _db;
public UserRoleController(IMyDB db)
{
_db = db;
}
[EnableQuery(PageSize = 20)]
public IActionResult Get()
{
return Ok(_db.UserRole().AsQueryable());
}
[EnableQuery]
public IActionResult Get([FromODataUri] string roletype)
{
return Ok(_db.UserRole().Find(roletype));
}
}
}

I have found out what is the problem. In the future if someone is working with OData this might help in countless hours of debugging.
The UserRole Class I have looks like below. Notice the data annotation [Key], that is what is causing the OData to ignore the path. I need to change the data Type to match the UserRole class "key" public IActionResult Get([FromODataUri] Guid roleid)
That fixes the problem. Hope this helps people in the future.
public class UserRole
{
[Key]
public Guid RoleId { get; set; }
public Role RoleType { get; set; }
public string RoleName { get; set; }
}

Related

What is the difference between Mapper.ProjectTo and Mapper.Map in Asp.net MVC core

When can we use Mapper.ProjectTo over Mapper.Map in Asp.Net core application? Use of ProjectTo method in Entity Framework Core, will it reduce the number of fields I query from the database to match the model if we add it in the beginning of the _mapper.ProjectTo statement? How will it reduces the query number of fields?
Instead of using this
_mapper.ProjectTo<CompareVarValdto>(_compareRepo.GetCompareDetailsByid(id))
we can use this right?
_mapper.Map<CompareVarValdto>(result)
ComapreVarValdto.cs
public class CompareVarValdto
{
public int CompareVarValId { get; set; }
public int CURRENT_CATEGORY_ID { get; set; }
public int Current_LaunguageId { get; set; }
public int Current_compareDimId { get; set; }
public string CONTENT { get; set; }
}
Controller get method code snippet
[Route("api/[controller]")]
[ApiController]
public class ComapareController : ControllerBase
{
private readonly ICompare _compareRepo;
private readonly IMapper _mapper;
public ComapareController(ICompare compare, IMapper mapper)
{
_compareRepo = compare;
_mapper = mapper;
}
[HttpGet("{id:int}")]
public IActionResult GetComapare(int id)
{
try
{
return Ok(_mapper.ProjectTo<CompareVarValdto>(_compareRepo.GetCompareDetailsByid(id)));
//VS
//var result = _compareRepo.GetCompareDetailsByid(id);
//return Ok(_mapper.Map<CompareVarValdto>(result));
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
compareRepo Database method
public IQueryable<CompareDim> GetCompareDetailsByid(int compareId)
{
return _context.CompareDim.Include("Launguage");
}
reference: automapper LINQ deep dive
I think the article explains your question.
If I understand the article right Mapper.Map works in-memory, Project to creates a expression-tree that needs to be parsed and understood by the underlying query provider.
I'm not sure if it will reduce the number of queried fields. My understanding/guess is, and I hope people will correct me, that ProjectTo is more efficient because the query in only executed after constructing the complete expression tree, and you use the query provider to execute the query (in SQL).
While working in memory: "(...)
The main problem people run into here is that typically that source object is some object filled in from a data source, whether it's a
relational or non-relational source. This implies that the original
fetch pulled a lot more information back out than we needed to."
this does not seem to be the case.

ASP.NET Core Web API - AmbiguousMatchException: The request matched multiple endpoints

I've been looking at this, but still cannot find a solution, here goes:
To return all players, I will pass in something similar to:
http://localhost:7777/api/teams/34fe3b6f-ba23-4657-820a-6c59dd49173a/players
To return a specific player on a specific team, I will pass in somethign similar to:
http://localhost:7777/api/teams/34fe3b6f-ba23-4657-820a-6c59dd49173a/players/f7de7974-9cbb-4c2c-884e-29036d6c2d76
I keep getting the following error:
System.ArgumentException: 'The route parameter name 'id' appears more than one time in the route template. '
Could someone please advise how to fix this?
[Route("api/Teams/{Id}/Players}")]
[ApiController]
public class PlayersController : ControllerBase
{
[HttpGet]
public IActionResult GetAllTeamPlayers(Guid id)
{
return Ok();
}
[HttpGet]
public IActionResult GetTeamPlayer(Guid id, Guid id2)
{
return Ok();
}
}
You should define the route parameters like this:
[Route("api/Teams/{teamId}/}")]
[ApiController]
public class PlayersController : ControllerBase
{
[HttpGet("players")]
public IActionResult GetAllTeamPlayers([FromRoute] Guid teamId)
{
return Ok();
}
[HttpGet("players/{playerId}")]
public IActionResult GetTeamPlayer([FromRoute] Guid teamId, [FromRoute] Guid playerId)
{
return Ok();
}
}

Issue on signalR dotnet core

Issue
Scenario:
SignalR version 1.0.0 RC1 Final
DotNet Core 2.0
Tipical: User - Posts - Comments models.
Issue:
When I send a model through websocket fails silently (no message is send to clients). It works fine if I set to null navigation property:
_context.Posts.Add(model);
_context.SaveChanges();
model.User.Posts = null; // <- removing this line fails silently
_hub.Clients.All.SendAsync("AddAsync", model);
How can I diagnose what is happens? Someone knows what is the reason?
Some unnecesary code details
User.cs
public Guid Id { get; set; }
// ...
public virtual List<Post> Posts { get; set; } = new List<Post>();
Post.cs
public Guid Id { get; set; }
// ...
public virtual User User { get; set; }
PostsController.cs
private IHubContext<PostsHub> _hub;
private DatabaseContext _context;
public PostsController(IHubContext<PostsHub> hub)
{
_hub = hub;
}
// ...
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] Post model)
{
// ...
_context.Posts.Add(model);
_context.SaveChanges();
model.User.Posts = null;
_hub.Clients.All.SendAsync("AddAsync", model);
// ...
}
With json convert Serialize the model to json and deserialize it again as Post object just before sending it.
If there is an error it should popup there, because if there is a dependency loop json convert should throw exception

How can I use my database tables etc Users table with ASP.NET Identity?

I have following tables:
Users, Groups, GroupUsers
I have my class like:
public class User
{
List<int> GroupIds;
}
I have a method in my Data Access Layer which returns a user after successful login with the list of all the group ids. How can I override or do something similar in identity to get information from that method?
I have searched the Internet a lot, watched YouTube tutorials, but no one is actually explaining it the way I need it. Can any one help?
First, use claims based security instead of role based: http://visualstudiomagazine.com/articles/2013/08/01/leveraging-claims-based-security-in-aspnet-45.aspx
I've also been retro-fitting an existing SQL based login system to work with identity management. Most of the work you're going to have to do lies within IdentityModel.cs. Specifically how you define ApplicationUser
public class ApplicationUser : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
I've overridden all 4 type parameters on the IdentityUser base class for my implementation, you may not need to do so, depends on how different your retrofit is from how Identity expects things to be.
The other main place you'll most likely have to customize things is within ApplicationDbContext where you'll have to set up where your user, group, and claims/role definitions reside with SQL.
I found these articles on typecastexception to be very useful:
http://typecastexception.com/post/2014/04/20/ASPNET-MVC-and-Identity-20-Understanding-the-Basics.aspx
http://typecastexception.com/post/2014/06/22/ASPNET-Identity-20-Customizing-Users-and-Roles.aspx
http://typecastexception.com/post/2014/04/20/ASPNET-Identity-20-Setting-Up-Account-Validation-and-Two-Factor-Authorization.aspx
http://typecastexception.com/post/2014/07/13/ASPNET-Identity-20-Extending-Identity-Models-and-Using-Integer-Keys-Instead-of-Strings.aspx
Overall there going to be a lot of trial and error in the process as you figure out what pieces of Identity you can utilize as is and where you need to plug in your own code.
Something else you may run into if your passwords aren't stored is having to provide your own implementation of PasswordHasher and plugging that in:
Asp.net Identity password hashing
I did' t get your question, if you want to override you have to mark the method virtual and inherit the class like this:
public class User
{
public virtual void YourMethod()
{
}
}
public class YourClass : User
{
public override void YourMethod()
{
}
}
If you want to separate the class to add some more mothods you can go like this:
partial class User
{
public static void YourMethod()
{
}
}
Create a UserInfo object
public class ApplicationUser : IdentityUser
{
public virtual UserInfo UserInfo { get; set; }
}
public class UserInfo : ComparableEntity
{
public string Email { get; set; }
public string FullName { get; set; }
public string KidName { get; set; }
public string MobilePhone { get; set; }
}
Then create a database context
public class DatabaseContext : IdentityDbContext<ApplicationUser>, IDatabaseContext
{
public IDbSet<UserInfo> UserInfos { get; set; }
}

AutoMapper Update Actions in ASP.NET MVC

This is probably quite straight forward for some, however I'm a bit confused and can't find a decent example. Say I'm using view models and my POST action takes in that view model. Typically I would do something along the following lines:
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
User user = Mapper.Map<UserViewModel, User>(uvm);
_repository.Update(user);
return RedirectToAction("Index");
}
Although this isn't the full picture. The mapping would work fine, however if I were to just update what I've mapped then it'd get rid of valuable data in the database because of course in this case I'm not updating the password or other details.
My repository looks something like this:
public void Update(User user)
{
User u = Session.QueryOver<User>().Where(x => x.UserName == user.UserName).SingleOrDefault();
if (u == null)
throw new Exception("User not found");
u.Forename = user.Forename;
u.Surname = user.Surname;
u.EmailAddress = user.EmailAddress;
}
[I'm using NHibernate so it'll save the object back to the DB once the session is closed (after the request has finished) automatically for me.]
So my question is, in my repository should I load the "User" entity, then update the values I want, and then save it back, or is there another method to do this? The reason I ask is because it seems a bit... "manual" if you see what I mean? Perhaps it is correct, but I just wanted to see opinions of those with more experience in this area.
Cheers
I use the following approach:
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
User user = _userRepository.FindById(uvm.Id);
user.Forename = uvm.Forename;
user.Surname = uvm.Surname;
user.EmailAddress = uvm.EmailAddress;
_userRepository.Update(user);
return RedirectToAction("Index");
}
UPDATE:
To address the comments about AutoMapper here's how to proceed:
Let's take for example the following classes:
public class UserViewModel
{
public string Forename { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
}
public class User
{
public string Forename { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
}
We don't want to modify the user password in the UI. So we express our intention to AutoMapper:
Mapper
.CreateMap<UserViewModel, User>()
.ForMember(dest => dest.Password, opt => opt.Ignore());
and then:
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
// Fetch the original model we would like to update
User user = _userRepository.FindById(uvm.Id);
Mapper.Map(uvm, user);
// At this stage the user model will have its
// Forename, Surname and EmailAddress properties
// updated from the view model and its Password property
// will remain the one we got from the repository
_userRepository.Update(user);
return RedirectToAction("Index");
}
UPDATE 2:
To address the question in the comments about configuring AutoMapper I usually use Profiles:
public class UsersProfile : Profile
{
protected override void Configure()
{
Mapper
.CreateMap<UserViewModel, User>()
.ForMember(dest => dest.Password, opt => opt.Ignore());
Mapper
.CreateMap<User, UserViewModel>();
}
}
and then have a registry class which registers all the mappers:
public class MappingsRegistry
{
public static void Configure()
{
Mapper.AddProfile(new UsersProfile());
Mapper.AddProfile(new SomeOtherProfile());
...
}
}
which is called in Application_Start:
MappingsRegistry.Configure();
Finally my controllers have a reference to the mapping engine:
public class UsersController : Controller
{
private readonly IUsersRepository _repository;
private readonly IMappingEngine _mappingEngine;
public ContratsFCController(IUsersRepository repository, IMappingEngine mapperEngine)
{
_repository = repository;
_mapperEngine = mapperEngine;
}
[AutoMap(typeof(User), typeof(UserViewModel))]
public ActionResult Update(int id)
{
var user = _repository.FindById(id);
return View(user);
}
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
if (!ModelState.IsValid)
{
return View(uvm);
}
var user = _repository.FindById(uvm.Id);
_mapperEngine.Map(uvm, user);
_repository.Update(user);
return RedirectToAction("Index");
}
}
Now all that's left is to instruct your DI framework to pass the Mapper.Engine property to the constructor and in your unit tests obviously substitute them with an appropriate mock.