Add object to database with username - c#

I am getting a simple object from a form in a MVC4 application
portfolio = {code: xxxxx, quantity: -10}
I need to add the Username to the database when I do this insert which I already know I can get from the HTTPContext.
What would be the best way to include this in the below code. I know I will need to change the object I am adding but what is the right way to do this?
public ActionResult Add(Portfolio portfolio)
{
var ctx = new MarginEntities();
ctx.Portfolios.Add(portfolio);
ctx.SaveChanges();
return RedirectToAction("Index");
}

Extend the Portfolio class to include the necessary property:
class Portfolio
{
public string Code { get; set; }
public int Quantity { get; set; }
public string Username { get; set; }
}
When the request comes from client, fields Code and Quantity are initialized, and Username is set to its default value, which is null. So simply initialize it before submitting to DB:
public ActionResult Add(Portfolio portfolio)
{
portfolio.Username = Session["Username"]; // or however the username is stored
var ctx = new MarginEntities();
ctx.Portfolios.Add(portfolio);
ctx.SaveChanges();
return RedirectToAction("Index");
}

You could use the User object, I take it all users are first authenticated?
User.Identity.Name
Your Portfolio object could then either have a string for the username or you could use a FK to the 'users' table, and get this ID by passing in the Name property from above.
You could then have either:
class Portfolio
{
...
public string Username { get; set; }
}
If you take this approach, then you would just pass the Portfolio object with the new Username property set.
or
class Portfolio
{
...
public int UserId { get; set; }
}
if you take this approach then you would need to request the UserId from EF context and then populate the Portfolio object with the returned UserId

Related

How to extend the ApplicationUser in ASP.NET MVC correctly?

This is my first attempt to use the ASP.NET identity with the builtin authentication. All previous attempts resulted in having a manual check for user credentials and then setting FormsAuthentication AuthCookie. But I had some problems with a signalR connection not having authentication information this way. So I started from scratch with the builtin authentication.
So I extended my ApplicationUser object with some fields:
public class ApplicationUser : IdentityUser
{
public long SteamId { get; set; }
public string Avatar { get; internal set; }
public string Name { get; internal set; }
public int Credits { get; internal set; }
public long? DiscordId { get; internal set; }
public DateTime? LastLogin { get; internal set; }
public DateTime RegisterDate { get; internal set; }
}
These fields will create new columns in my AspNetUsers table. The problem is, I can't access these values in my views. For that I need to use claims if I understand correctly. These claims are stored in another table called AspNetUserClaims. So I have to add those claims to the user
await UserManager.AddClaimAsync(user.Id, new Claim("Avatar", user.Avatar));
and creating a extension method to get the avatar from the principal
public static class ClaimsPrincipalExtension
{
public static string GetAvatar(this ClaimsPrincipal principal)
{
var avatar = principal.Claims.FirstOrDefault(c => c.Type == "Avatar");
return avatar?.Value;
}
}
Now I can access the avatar in my view
#(((ClaimsPrincipal)User).GetAvatar())
I don't think that's a really good and clean way to do this, but this is the first time I am using it, so I don't know what's the best practices to do. There are three main reasons why I don't like it:
The avatar is stored twice, once in the AspNetUsers table as column and once as a new entry in AspNetUserClaims
Fields like SteamId, Credits or RegisterDate are saved as string in the AspNetUserClaims table, and I have to convert them to int, long or DateTime in the extension method
I have to write an extension method for every property I'll add to the ApplicationUser
What is the best way to handle additional fields?
Might it be an option to create a new object called AdditionalUserInformation and store the json serialized string as claim and just have one extension method to return the object? Then the properties would have the correct type.
Or is there a way to access the properties of the ApplicationUser in the view?
Or is the problem the use of those in the view? Should I access them in the controller and create a Model for the view containing all information? What about a _Layout page or a _navigation partial view then? They also might need the information of the user. I think I can't feed them with the controllers.
I also checked some examples. Mostly they add those extension methods and mostly just string properties.
Examples
How to extend available properties of User.Identity
How should I access my ApplicationUser properties from within my MVC 6 Views?
I am currently kinda stuck here on finding the best and maybe clean solution.
You can access AspNetUsers table with the name "Users" from your DbContext. First query AspNetUsers with current user's username or userId, then fill your ViewModel and send it to the view. The following code shows what I described:
[Authorize]
public ActionResult UserTopNavBar()
{
var userTopNavBarViewModel = new UserTopNavBarViewModel();
using(ApplicationDbContext _db = new ApplicationDbContext())
{
var user = _db.Users.FirstOrDefault(a => a.UserName == User.Identity.Name);
if (user != null)
{
userTopNavBarViewModel.Name = user.FirstName + " " + user.LastName;
userTopNavBarViewModel.Picture = user.Picture;
userTopNavBarViewModel.Id = user.Id;
}
}
return PartialView(userTopNavBarViewModel);
}
And this is my ViewModel
public class UserTopNavBarViewModel
{
public string Name { get; set; }
public byte[] Picture { get; set; }
public string Id { get; set; }
}

Why are the JSON objects empty?

I've got a GET entry point on UsersController. But this one is responding an array of empty objects. When I debug the entry point, the list (IEnumerable<UserViewModel>) is not empty and UserViewModels are not empty either.
But here is what it does respond:
[{},{},{},{},{},{},{},{},{},{},{},{}]
And the controller code:
[HttpGet]
public async Task<IEnumerable<UserViewModel>> Get()
{
var u = _stObjMap.Default.Obtain<UserTable>();
using (var ctx = new SqlStandardCallContext())
{
var a = await ctx[u].Connection.QueryAsync<UserViewModel>("SELECT UserId, UserName, PrimaryEMail, CreationDate from CK.vUser where UserId <> 0 and UserId <> 1");
return a;
}
}
I really don't think that the problem is coming from the controller.
I'm using Dapper.I really don't know what is happening. And I have to write a lot because I can't edit this post
Most likely the UserViewModel has no public properties defined.
Which is why no key value pairs are displayed when the object is serialized to JSON.
Based on the query, make sure there are matching properties in the model for the Dapper query to map the selected columns
public class UserViewModel
public int UserId { get; set; }
public string UserName { get; set; }
public string PrimaryEMail { get; set; }
public DateTime CreationDate { get; set; }
}

ViewModel Object Convert to Entity Framework Object

Goal: to save ViewModel object by Entity Framework. I have UserViewModel object which has list of UnitViewModel. Then, I have a UserAdapter class which converts UserViewModel into Entity Framework User object (see Convert()below how).
Now, my question is how do I convert this list of UnitViewModel to its corresponding Entity Framework Unit list? - Do I have to get each object from DB Context by calling something like context.Units.Where(u=>myListofUnitIDs.Contains(u.UnitID))?
public class UserViewModel
{
public Guid? UserID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public DateTime? CreateTime { get; set; }
public List<UnitViewModel> UserUnits { get; set; }
}
public class UnitViewModel
{
public Guid UnitID { get; set; }
public string Name { get; set; }
public int? SortIndex { get; set; }
public DateTime CreateTime { get; set; }
public bool Assigned { get; set; }
}
public class UserAdapter
{
public static User Convert(UserViewModel userView)
{
User user;
if (userView.UserID.HasValue)
{
using (var provider = new CoinsDB.UsersProvider())
{
user = provider.GetUser(userView.UserID.Value);
}
}
else
{
user = new User();
}
user.FirstName = userView.FirstName;
user.LastName = user.LastName;
user.Password = StringHelper.GetSHA1(userView.Password);
user.UserName = user.UserName;
user.CreateTime = DateTime.Now;
// Problem here :)
// user.Units = userView.UserUnits;
return user;
}
}
UPDATE: The main concern here is that I have to retrieve each Unit from database to match (or map) it with ViewModel.Unit objects, right? Can I avoid it?
For your information, this operation is called as Mapping mainly. So, you want to map your view model object to the entity object.
For this, you can either use already existed 3rd party library as AutoMapper. It will map properties by reflection which have same name. Also you can add your custom logic with After method. But, this approach has some advantages and disadvantages. Being aware of these disadvantages could help you to decide whether you must use this API or not. So, I suggest you to read some articles about advantages and disadvantages of AutoMapper especially for converting entities to other models. One of such disadvantages is that it can be problem to change the name of one property in the view model in the future, and AutoMapper will not handle this anymore and you won't get any warning about this.
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit = Mapper.Map<UnitViewModel, UserUnit>(item);
user.Units.Add(userUnit);
}
So, I recommend to write your custom mappers.
For example, I have created a custom library for this and it maps objects lik this:
user.Units = userView.UserUnits
.Select(userUnitViewModel => userUnitViewModel.MapTo<UserUnit>())
.ToList();
And I am implementing these mapping functions as:
public class UserUnitMapper:
IMapToNew<UnitViewModel, UserUnit>
{
public UnitViewModel Map(UserUnit source)
{
return new UnitViewModel
{
Name = source.Name,
...
};
}
}
And then in runtime, I am detecting the types of the objects which will be used during mapping, and then call the Map method. In this way, your mappers will be seperated from your action methods. But, if you want it urgently, of course you can use this:
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit= new UserUnit()
{
Name = item.Name,
...
};
user.Units.Add(userUnit);
}

MongoDB best practice for referencing

I'm wondering what the best practice for modelling by using references would be given situation under. I'm using MongoRepository library.
public class User : Entity
{
publis string Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class Post : Entity
{
public string Id { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public DateTime Added { get; set; }
public User Owner { get; set; }
}
When storing the Post I want only reference to Owner (User) object instead of whole object underlying.
Currently I'm doing it like this, not knowing of better way...
var post = new Post
{
Title = "Example title",
Summary = "asd asd",
Added = DateTime.Now,
Owner = new User { Id = "someExistingUserId" }
};
postRepository.Update(post); //Save
..
//Then to get the post
var post = postRepository.GetById("previouslySavedPostId");
post.Owner = userRepository.GetById(post.Owner.Id);
return post;
userRepository and postRepository are of MongoRepository type.
Is this the correct approach to solving my problem using MongoDB with C#/MVC(4)?
You can use MongoDBRef object instead of User object.
public class Post : Entity
{
public string Id { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public DateTime Added { get; set; }
public MongoDBRef Owner { get; set; }
}
Then you can:
var mongo = new Mongo(config.BuildConfiguration());
mongo.Connect();
var DB = mongo.GetDatabase(_dataBaseName)
var post = new Post();
post.Owner = new MongoDBRef("User", userId); // First parameter is a mongoDB collection name and second is object id
// To fetch object referenced by DBRef you should do following
var owner = DB.FollowReference<User>(post.Owner);
Mongo is a document database and if you are used to using sql server it requires a slightly different way of thinking.
As you don't want the user password details in every single post, the way i would probably do it is to create a new class to contain any user info that might be required to display a post.
public class PostOwnerInfo
{
public string UserId { get; set; }
public string Name { get; set; }
}
Update your post entity, replacing the Owner property with an OwnerInfo property, of type PostOwnerInfo.
Then when you create a new post, do the following.
var user = userRepository.GetById(someExistingUserId);
var post = new Post
{
Title = "Example title",
Summary = "Example summary",
Added = DateTime.Now,
OwnerInfo = new PostOwnerInfo
{
UserId = user.Id,
Name = user.Name
}
};
postRepository.Update(post);
This way when you query for a post it will have all the user info that you require to display the post in it's OwnerInfo property with no further queries required.
var post = postRepository.GetById(previouslySavedPostId);
// post.OwnerInfo will contain user info
There is a certain amount of data redundancy, but in an document database this is how i would do it.
If you need the full user info for any reason just do a seperate query for it as you were doing before.
The idea is that you store all the user info you need for a post in a child document of the post, so you shouldn't need to do a seperate query for the user.
If the user data chages, just update the UserInfo field on all posts made by your user.
Your user data will rarely change, but you will query for posts very often.

Bind 2 table together (one to many relationship)

I am pretty new to c#, EF Code First and all that, so my question might be an easy one.
I am trying to create a very simple login. Each user must have a type (admin or client). How can I bind the usertype to my user table without generating a new type each time I insert a new user in the DB?
Here are my code first class:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool Active { get; set; }
public UserType TypeId { get; set; }
}
public class UserType
{
public int Id { get; set; }
public string Type { get; set; }
}
public enum TypeEnum
{
Admin,
Client
}
When I launch the app, I want to be able to create 2 tables:
Users which is empty
UserTypes which must contain 2 types (Admin and Client).
Then, everytime I register a new user, so everytime I add a user to the Users table, I want to be able to use the UserTypes table.
When I launch the app, I want to be able to create 2 tables...
Not sure if I understand this correctly but you can seed initial data into the database with EF Code-First. An example how to do that is here:
Entity Framework Inserting Initial Data On Rebuild
If you really want to recreate the tables with every launch of your application you can use the DropCreateDatabaseAlways<T> initializer as mentioned in the example.
Then, everytime I register a new user, so everytime I add a user to
the Users table, I want to be able to use the UserTypes table.
For this you would load the existing UserType you want to assign from the database so that it is attached to the context and then create the new user:
using (var context = new MyContext())
{
var userType = context.UserTypes
.Single(u => u.Type == TypeEnum.Admin.ToString());
var newUser = new User { TypeId = userType, Username = ... etc. };
context.Users.Add(newUser);
context.SaveChanges();
}
Attaching to the context - by either loading from the database or calling Attach explicitely - makes sure that the UserType is not duplicated, i.e. no INSERT command will be sent to the database for the UserType.
With new version of EF (currently beyond the offical 4.1 version: Entity Framework June 2011 CTP) you can also do that:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool Active { get; set; }
public UserType Type { get; set; }
}
public enum UserType
{
Admin = 1,
Client = 2,
}
The data will be saved as integer in your database but within your application you can use your enum like this:
var newUser = new User { Type = UserType.Admin, Username = ... };
context.Users.Add(newUser);
context.SaveChanges();

Categories