ASP.NET MVC placing userID in hidden field - c#

I am using ASP.NET MVC 5 Razor
I am trying to apply the membership userID to a hidden field so that I can associate table data to a spceific user.
(users completes a form that is stored in a table, userID used to associate to login profile)
I just don't know how to do this and is an important part of my current project and future projects.
Any guidance, advice, links to solutions would be of great help as I am completely at a loss with this.
I tried passing the data from the model class for the view but I get an error saying "The name 'User' does not exist in the current context"
this is an extract of my model class
using System;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Globalization;
using System.Web.Security;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace mySite_Site.Models
{
[Table("accountInfo")] // Table name
public class accountInfo
{
[Key]
public int AccountID { get; set; }
public int UserIdent { get; set; } //this is the field that would store the userID for association
public string LastName { get; set; }
public string FirstName { get; set; }
public string Locality { get; set; }
public string EmailAddress { get; set; }
public bool Active { get; set; }
public DateTime LastLoggedIn { get; set; }
public string UserIdentity = User.Identity.GetUserId();
}

Expanding on Brandon O'Dell's answer, using "Membership" in that block of code didn't work for me (unhandled errors). Nevertheless, I think his approach to this solution is great because it means you can call the current user's Id from practically anywwhere. So, I went on ahead and played a little bit with the code, and voilá!.
In case using "Membership" doesn't work for you as well, try this one:
using <your project's name>.Models
public class GeneralHelpers
{
public static string GetUserId()
{
ApplicationDbContext db = new ApplicationDbContext();
var user = db.Users.FirstOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
return user.Id;
}
}
This one gets the whole user, so, you can create even more methods inside this "GeneralHelper" class (or whatever name you wish to give it) to get the current user's info and use it in your application.
Thanks, Brandon!

You just need something like this, assuming your ViewModel has the user profile on it.
#Html.HiddenFor(m=>m.UserProfile.UserId)

Since your model is not in the controller, you need to explicitly tell the code Where the user object is, which is contained in the HttpContext. So, update this line here:
public string UserIdentity = User.Identity.GetUserId();
to the following
public string UserIdentity = HttpContext.Current.User.Identity.GetUserId();
The controller and view base classes have a reference to the current HttpContext, which is why you can shortcut in those items and simply use User.Identity. Anywhere else in your project, you will need the fully qualified HttpContext.Current.User.
Edit
In further looking at your code, it looks like you are trying to save the user Id as a column in your database. In that instance, I think (based on your code sample) that you should remove that last part - public string UserIdentity = User.Identity.GetUserId();. When you save a new account info object, that is where you would save the user id.
var info = new accountInfo();
accountInfo.UserIdent = HttpContext.Current.User.Identity.GetUserId();
db.accountInfos.Add(info);
db.SaveChanges();

Why not just create a static helper class?
public static class UserUtils
{
public static object GetUserId()
{
return Membership
.GetUser(HttpContext.Current.User.Identity.Name)
.ProviderUserKey;
}
}

Related

Using a Database Context in multiple projects within the same solution

I'm currently working on a program that is being used to generate PDF's and documents. There are two different use cases, one being an automated process and the second being a manual process where data can be edited via a front-end app.
The solution has 2 Projects in it, the first for the automated part, and the second for the manual part.
However, since the two processes make use of the same data and templates, I've split the solution into two parts, this will allow me to set it up in a way in which I only need to maintain models/templates once.
My database context looks like this:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RefundTracker.Models
{
public class DatabaseContext : DbContext
{
public DatabaseContext()
:base("Prod")
{
}
public DbSet<Referral> Referrals { set; get; }
public DbSet<ReferralAppointment> ReferralAppointments { set; get; }
public DbSet<ReferralPayment> ReferralPayments { set; get; }
public DbSet<BankDetails> BankDetails { set; get; }
public DbSet<ReferralAppointment_History> ReferralAppointment_History { set; get; }
public DbSet<ReferralPayment_History> ReferralPayment_History { set ; get; }
public DbSet<IsInUse> IsInUse { set; get; }
}
}
In terms of projects, I have a project called "RefundTracker" and another called "MailMergeTPA".
The context provided above, together with all of the models, are located in the "RefundTracker" project.
I would like to make use of these models and context in the "MailMargeTPA" project as well.
I referenced the "RefundTracker" in "MailMergeTPA" project, however, no results when using the context here. (When I access a function that get a list of names for instance, I get the full list in "RefundTracker", however, I get no results when I use the same function in "MailMergeTPA".
Code Example:
public BankDetails GetBankDetails(Referral record)
{
string bName = record.bankName.Trim();
try
{
BankDetails bankDetails= new BankDetails();
List<BankDetails> bankDetails = new List<BankDetails>();
using (DatabaseContext db = new DatabaseContext())
{
bankDetails = db.BankDetails.SingleOrDefault(a => a.BankName == bName);
}
return bankDetails;
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
return null;
}
I would like to make use of this exact function in both projects.
Could you kindly help me with some advice? (Please go easy on me in the comments, I'm still fairly new to EF)
I've tried referencing the project, no result.
I've read up on interfaces, however, I'm unsure as to how I would incorporate this.

Mapping a User entity into a User DTO in .NET Core

I'm developing a web app that contains a User entity that is derived from .NET Core's IdentityUser. Lets suppose there is another entity called Comment which has a relation to a user (the user who posted the comment):
public class User : IdentityUser
{
public string SomeExtraField { get; set; }
}
public class Comment
{
//Owner (Creator) of the feedback
public User User { get; set; }
//body of the comment
public string Body { get; set; }
}
Now suppose I have an API endpoint that returns all of the comments in the system. If I query for all comments and include the User relation, when the object gets serialized, everything in the User class is serialized and sent to the client (including the users hashed password, etc). Obviously I don't want this. So I've created a CommentService layer that grabs the Comments from a CommentRepository. From my understanding, the service layer should do the job of mapping the raw Comment object into a Comment DTO, which only contains data that should be sent to the client. I've defined a comment and user DTO like this:
public class UserOutput
{
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
public class CommentOutput
{
public UserOutput User { get; set; }
public string Body { get; set; }
}
Then in my service layer I have something like the following:
//Fetch all comments
var list = await _repository.ListAsync();
//Map comments to DTO
var result = list.Select(x => new CommentOutput
{
Body = x.Body,
User = new UserOutput
{
Id = x.User.Id,
SomeExtraField = x.User.SomeExtraField,
}
});
This all seems to work great. However I can foresee one problem. Lets say I have a large system with Comments, Posts, Likes, Private Messages, etc. I can map them all in a similar fashion above. Then one day I decide to add another field to the UserOutput DTO. Now I have to go through potentially hundreds of mapping code like the sample above to map the new field properly, and whats worse is the compiler wont tell me if I've missed anything. I would like to have a function somewhere that maps a User to a UserOutput but I don't know where it should go.
I've seen some suggestions to put a constructor to the DTO that does the mapping:
public class UserOutput
{
public UserOutput(User user)
{
Id = user.Id;
SomeExtraField = user.SomeExtraField
}
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
but I've seen people against this because it tightly couples the DTO with the Entity. I've also seen suggestions of using Auto Mapper but is also seems an equal amount of people are against it.
Where should I place code that can perform these DTO->entity and entity->DTO mappings so I don't repeat myself all over the place?
Try to check out AutoMapper.
This library will help you to map the Entity Class into the ViewModel.
The way to use it is pretty straightforward.

C# EF Required Attribute not recognized

I am creating an app that uses a database (SQLite). I am using entity framework and ADO.NET to interact with it.
I have a seprate Models project in my app that contains all of my Database models.
Now I want to mark some of my class properties as required to reflect the "NOT NULL" option in my database. But if I add the [Required] Attribute from DataAnnotations namespace I get a compiler error saying it cannot be resolved.
Here is how my class looks like :
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ReflowModels
{
public class Tag
{
public Tag()
{
this.Options = new HashSet<Option>();
}
public int Id { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Option> Options { get; set; }
}
}
I have also added a reference to EntityFramework.dll in my project.
you need to add this to your using block
using System.ComponentModel.DataAnnotations.Schema;
you need to add this to your using block
using System.ComponentModel.DataAnnotations;
In case it still doesn't work, maybe you should add it to your References

what 's the use of creating a metadata class and a partial class for the model class c#

I just joined a new company and my manager just joined too, and he wants to change the way we program. basically do what he does. I'm wondering what's the difference, pros, cons, limitation and problems if there'll be any..here's the sample
namespace Models //this is the model part of from edmx
{
using System;
using System.Collections.Generic;
public partial class MyModelClass
{
public int ID { get; set; }
public Nullable<System.DateTime> PostDate { get; set; }
public string MyContent { get; set; }
}
}
this is the metadata:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Models
{
public class MyModelMetaData
{
//he wants all data annotation here
public int ID { get; set; }
public Nullable<System.DateTime> PostDate { get; set; }
public string MyContent { get; set; }
}
}
this is the partial:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Models
{
[MetadataType(typeof(MyModelMetaData))]
public partial class MyModelClass or MyModelClassPartial
{
//He wants the programming algorithm to go here
}
}
Please enlightened me. and he wants to create different metadata and partial classes per model class..way too many files involved.
thank you..i need an answer as to why..if you think his method is good..I will do this..but if you think this will cause problem in the future and more coding will be involve..i need to know
The first class you show, the entity classes, are generated from the database every time you save the EDMX (or when you execute the T4 Template).
This causes the file containing public partial class MyClass under the EDMX to be regenerated. So you cannot alter it, because the next time someone refreshes a table or adds one, your changes are gone.
That's why entity classes are generated as a partial: so you can create another partial to the same class to do your modifications in.
However, if you want to annotate your entity's properties with metadata, you cannot redefine the same property in the other partial class: the same name can only be used by one member of a type. So you can't do this:
// Entity class
public partial class FooEntity
{
public string Name { get; set;}
}
// User-created partial class
public partial class FooEntity
{
[Required]
public string Name { get; set;}
}
Because that code expresses you want two properties named Name in the FooEntity class, which is not valid.
So you'll have to come up with another way to add metadata to the type. Enter the [MetadataType] attribute. This works by creating a new class with the same properties as the class to be annotated. Here, using reflection, the metadata is resolved based on member name.
So when you create a metadata class for the above annotation:
public class FooEntityMetadata
{
[Required]
public string Name { get; set;}
}
You can apply it to the user-created partial:
// User-created partial class
[MetadataType(typeof(FooEntityMetadata))]
public partial class FooEntity
{
}
And also, in the latter partial, you can add members that add functionality to the entity model. New ([NotMapped]) properties and new methods for example.
I think the one use could be to not pollute the main class.
For example if you have a lot of attribute for validation (using dataannotation) and you don't want to have them in the main class you could use the MetadataTypeAttribute for that.
Another use could be if your class is auto-generated and you need to add some decoration (more attributes) to your properties without changing the autogenerated code.

Retrieving records from another SQL Server database - Umbraco

I'm working on a website, where I need to retrieve pricelists, from another database on the same SQL Server as my Umbraco database.
It's a requirement that it has to be in a separate database.
I have made a new connection string Pricelist and used EF database-first.
PriceList repository:
namespace UmbracoCMS.Repository{
using System;
using System.Collections.Generic;
public partial class Prisliste
{
public string Kode { get; set; }
public string Speciale { get; set; }
public string Ydelsesgruppe { get; set; }
public string Gruppe { get; set; }
public string Ydelse { get; set; }
public string Ydelsestekst { get; set; }
public string Anaestesi { get; set; }
public string Indlæggelse { get; set; }
public Nullable<double> Listepris { get; set; }
public Nullable<int> WebSort { get; set; }
public string YdelsesTekstDK { get; set; }
public string Frapris { get; set; }
public Nullable<int> Sortering { get; set; }
}
}
PriceListController class:
using System;
using System.Linq;
using System.Web.Mvc;
using UmbracoCMS.Repository;
namespace UmbracoCMS.Controllers{
public class PriceListController : Umbraco.Web.Mvc.SurfaceController {
[HttpGet]
public PartialViewResult GetPriceList(string contentTitle){
var db = new PricelistContext();
var query = from b in db.Prislistes orderby b.Speciale select b;
Console.WriteLine("records in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Speciale);
}
return PartialView("~/views/partials/PriceList.cshtml");
}
}
}
What I want is to load the prices for a treatment, based on a property on the document type. I'm just not sure how do this in umbraco since I'm fairly new a umbraco.
So when a treatment page is requested, I need to take the property ContentTitle value. Use it to retrieve all records with the same Speciale and display them in a list/table.
With a query
.where(b.Speciale = contentTitle)
It would be great if someone could help a little, or lead me in the right direction.
Also is it possible to do it in the same http request? Or should I use partial view or macros to both get the properties of the document type, from the umbraco database, and the records from the pricelist database at the same time when a user go to the treatment page?
Or is there a better way to do this?
Update:
Thanks a lot, for the great answer Ryios.
I got a question more.
using System;
using System.Linq;
using System.Web.Mvc;
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult GetPriceList(string contentTitle)
{
PricelistContext.RunInContext(db =>
{
var result = db.Prislistes.OrderBy(p => p.Speciale);
});
return View(result);
}
}
}
I got it working, so it call the method and the data from the Pricelist Database is shown in:
var result = db.Prislistes.OrderBy(p => p.Speciale);
Now I just need to get the list of prices out to the view again, so I can show a list or table of the prices.
Do you have a suggestion on how I can this in Umbraco. Normally I would return a ViewModel in MVC like:
return View(new ListViewModel(result));
and use it in the view like:
#model Project.ViewModels.ListViewModel
So I can loop through it.
But I want to still have the properties from the the "Home"/"TreatmentPage" Document type.
Should I do it with a partialView or is there a better way?
Solved
I thought I wanted to share it, if anyone else is in a similar situaction.
Controller:
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public PartialViewResult PriceList(string contentTitle)
{
List<Prisliste> result = null;
PricelistContext.RunInContext(db =>
{
result = db.Prislistes.Where(p => p.Speciale == contentTitle)
.OrderBy(p => p.Speciale).ToList();
});
var model = result.Select( pl => new PrislistVm()
{
Speciale = pl.Speciale,
Listepris= pl.Listepris
});
return PartialView(model);
}
}
}
ViewModel:
namespace UmbracoCMS.ViewModels
{
public class PrislistVm
{
public PrislistVm()
{
Results = new List<Prisliste>();
}
public List<Prisliste> Results { get; set; }
public string Speciale { get; set; }
public double listepris { get; set; }
}
}
View/PriceListSurface:
#model IEnumerable<UmbracoCMS.ViewModels.PrislistVm>
#{
ViewBag.Title = "PriceList";
}
<h2>PriceList</h2>
#foreach (var item in Model)
{
#item.Speciale
#item.Listepris
}
Your going to have a memory leak if you load your EF context like that. I recommend creating a method to wrap it for you with a llambda callback. Put it in your context class.
public static void RunInContext(Action<PricelistContext> contextCallBack)
{
PricelistContext dbContext = null;
try
{
dbContext = new PricelistContext();
contextCallBack(dbContext);
}
finally
{
dbContext.Dispose();
dbContext = null;
}
}
//Example Call
PricelistContext.RunInContext(db => {
var result = db.PrisListes.OrderBy(p => p.Speciale);
//loop through your items
});
To get the Value of the DocumentType, it depends on the calling context. Assuming you are using a Razor Template that is attached to the document type, that is associated with a Content Page.
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = "ContentPageLayout.cshtml";
}
#* Call GetPriceList on PriceListController with Parameter contentTitle *#
#Html.Action("GetPriceList", "PriceListSurface", new { contentTitle = Model.Content.GetPropertyValue<string>("ContentTitle") });
In the above example, I have created a document type with a property called ContentTitle that is associated with a view called ContentPage. Then I created content in the backoffice Content section called "Home" that uses the document type. Giving me a url like
http://localhost/home
Also, your SurfaceController will not work. Umbraco's logic for mapping the routes for surface controllers has some requirements for your surface controller's naming conventions. You have to end the name of the class with "SurfaceController" and then it get's called PriceListSurfaceController, then it maps the controller with a name of "PriceListSurface".
Here's the documentation for the SurfaceController features.
http://our.umbraco.org/documentation/Reference/Mvc/surface-controllers
Using a surface controller is the right logic. It's not good practice to have your Data Layer code calls in the UmbracoTemplatePage. 1, because RazorTemplates are interpreted/compiled and SurfaceController's are JIT compiled int the dll, so SurfaceController code is WAY faster. 2 Because you can make asynchronous Controller calls in MVC Razor. If it was all in the view it would make it really difficult to convert everything to be asynchronous. It's best to keep server side logic in a controller.
Optionally, you can Hijack an Umbraco route and replace it with a custom controller that doesn't have to inherit from SurfaceController, which makes it possibly to surface content to the browser that is or isn't part of umbraco.
http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers
You can also create a new section in the backoffice to manage your Price List "the ui framework for building one is written against AngularJS"
http://www.enkelmedia.se/blogg/2013/11/22/creating-custom-sections-in-umbraco-7-part-1.aspx

Categories