0

I've created my incredibly simplistic model:

public class ImageModel
{
    public int Id { get; set; }
    public string FileName { get; set; }
}

And now I want to store the logged-in user with the record. Presumably, I would do this by adding another property:

public User User { get; set; }

Which Visual Studio is telling me is telling me is in

using System.Web.Providers.Entities;

Assuming that's the right User class that corresponds with the presently authenticated user, how do I save that with my model?

My Create action looks like this:

    [HttpPost]
    public ActionResult Create(ImageModel imagemodel)
    {
        if (ModelState.IsValid)
        {
            db.ImageModels.Add(imagemodel);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(imagemodel);
    }

I imagine I would want to add something like

 imagemodel.User = User;

Just above db.ImageModels.Add, but those appear to be two different types. The User object in Controller appears to be an IPrincipal which really doesn't seem to hold much information at all.

How do I get the rest of the user data for the authenticated user? What do I need to assign imagemodel.User to? Is that even the way to do it, or do I need to explicitly tell it I just want to save the User ID (I'm assuming this much it could figure out) -- and if so, how do I keep a User object on my model such that it points to the real User object (not just an ID), and how do I get the User ID for the currently logged in user?

mpen
  • 272,448
  • 266
  • 850
  • 1,236

1 Answers1

2

It is dependent upon what technology you are using to manage logons or sessions.

Inside the controller method, you probably just want to set your model property to the value in 'User.Identity.Name', which is a string value.

That assumes the user is logged in and that you have forms authentication configured. You've probably previously authenticated the user, and given them a token (basically just an encrypted cookie) containing the value of '.Name', via the FormsAuthentication.SetAuthCookie method.

So, to keep things very simple, your Image model should probably just have a Username string property. If you have access to the user identity table, you might want to store a reference to the related user instead.

public class ImageModel
{
    public int Id { get; set; }
    public string FileName { get; set; }
    public string Username { get; set; }
}

Controller...

[HttpPost]
public ActionResult Create(ImageModel imagemodel)
{
    if (ModelState.IsValid && User.Identity.IsAuthenticated)
    {
        imagemodel.Username = User.Identity.Name;
        db.ImageModels.Add(imagemodel);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

The interfaces exposed without knowing what provider you are using are very minimal.

IPrinicipal User
    bool IsInRole(string role)
    IIdentity Identity
        string AuthenticationType
        bool IsAuthenticated
        string Name

That's it.

Once you select a provider or decide to implement a custom one there's a whole range of SO articles that will fall into your lap.

You may also be better served looking for ASP.NET references than MVC references when researching this topic.

Community
  • 1
  • 1
shannon
  • 8,664
  • 5
  • 44
  • 74
  • `Cannot implicitly convert type 'string' to 'System.Web.Providers.Entities.User'`. I'm not really sure how that's supposed to work. Presumably `User.Identity.Name` returns either my name or username, but not a user object nor a user ID, so... how's that going to work? This is a brand new MVC4 application, I'm not doing anything fancy. Whatever authentication came out of the box, that's what I'm using. – mpen Aug 31 '12 at 03:04
  • You won't want to serialize the whole User object into your data repository. It includes state information, like whether or not you are currently authenticated. What you probably want to store instead is a unique identity for the user, which is probably just their login name, and that's what is typically in the User.Identity.Name string in the typical setup. – shannon Aug 31 '12 at 03:07
  • No, of course I don't want to store the whole object. I figured it would be smart enough to use the PK for the user class automatically. Is that in fact the login? I thought there were would be a numeric PK. In either case, you're telling me I have to change my model to store a string or integer instead? If so, can I create a property on said model to retrieve the full information and have the framework be smart enough to "join" the user table automatically via this propery when necessary? – mpen Aug 31 '12 at 03:13
  • I think I'm missing something here. I really have no idea what it's using to authenticate me, or where it's storing this information. I don't see any "user" table in SQL server database, and I really have no idea what information this mysterious user object actually stores. However, I don't like the idea of storing strings on my ImageModel; can I use something else? And how would I retrieve the actual User object off my ImageModel then? Do I actually have to write some kind of query to pull the user using the UserName? Can't I just go `myImageModel.User.SomeUserProperty`? – mpen Aug 31 '12 at 03:20
  • Well, if you want it to do the work of getting the PK for the User, you need to cast it to the provider-specific identity type. For example, Passport identity has a PUID. FormsIdentity itself doesn't necessarily have any PK associated with it. If I'm not mistaken, the ASP.NET membership provider uses the login id as the PK. – shannon Aug 31 '12 at 03:25
  • Ah..ok. This is starting to make a tiny bit more sense. They've only given me access to this generic interface so that we can easily swap out the user provider with something else, which is why I'm having trouble getting anything concrete out? In that case, I think I need to figure out which provider I want to use and then come back to this. But the basic idea is that I have to type-cast this `User` or `User.Identity` object to the specific provider I'm using, and then I should be able to get the information I need? – mpen Aug 31 '12 at 03:31
  • http://msdn.microsoft.com/en-us/library/aa478949.aspx Here's the schema of the default ASP.NET membership table, "sqlmembershipprovider". The PK is a GUID. If you want to store that instead of the username, there is probably a method on the membership provider to get it. – shannon Aug 31 '12 at 03:33
  • Yes, Mark, that's true. The identity might even be a local Windows account depending on the authentication configuration. Unfortunately, you will be dealing with a bunch of legacy technologies when you research the available providers. – shannon Aug 31 '12 at 03:40
  • Mark, please let me know if I can clarify anything else in order to answer your original question. – shannon Sep 01 '12 at 05:08
  • Well, as I understand it, you *can* include another entity as a property of your model, and it will create a proper foreign-key relationship using the PK of said model; the problem seems to be that I don't know what model/entity I should be creating a link to. Ideally, I'd like to use OpenID for authentication, and there appears to be some sort of library included in MVC4, but the tutorials seem to be either dated, or for some kind of "forms" application, which is not what I want. So, firstly I need to figure out how to integrate OpenID, how to define my own user model and get the... – mpen Sep 01 '12 at 09:56
  • ...framework to use it. Then figure out whether I need to be casting this "User" property of the controller, "User.Identity" or this "HttpContext.Current.User" property or somesuch I've heard about, but doesn't seem to exist. And then figure out how to create the proper linkage... so I've got a lot to learn yet before I can even assess if your answer is even what I'm looking for. Edit: Library = http://www.dotnetopenauth.net/. – mpen Sep 01 '12 at 09:59
  • You can include another *Entity*, but not a random *Object*. The Object must be an Entity connected to the same context as the Entity you are saving, and if you want your User.Identity to return an EF Entity, you have some customization to do. – shannon Sep 01 '12 at 10:01
  • Can you recommend some tutorials for MVC4 on how to set up my own user class/model? Best I've found is these guys: http://www.asp.net/mvc/tutorials but it doesn't seem to talk about how to add my own user class/create my own provider, or link it with other models. – mpen Sep 01 '12 at 10:10
  • Yeah, OpenID is great, probably a good way to go. It does include a Linq to Entities sample too, so you are off to a good start, if you want to assign an entity there. – shannon Sep 01 '12 at 10:19
  • Here, http://www.west-wind.com/weblog/posts/2009/Sep/17/Integrating-OpenID-in-an-ASPNET-MVC-Application-using-DotNetOpenAuth , Rick Strahl has good info related to what you are doing. Here's a brief example http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal#1769727 Be aware that it isn't hard at all... the complex part is subclassing the view and controller so you don't have to cast your .User to your CustomIPrincipal all the time. After subclassing them, you need to decorate your controllers and edit your web.config for views to take effect too. – shannon Sep 01 '12 at 10:35
  • Sorry about that, I had to build that last anchor tag myself, and it went to the wrong answer: http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal#10524305 If you google it, the keywords you are looking for are "custom iprincipal" or "custom iidentity". That part isn't specific to MVC. The view and controller are... here are links on those... – shannon Sep 01 '12 at 10:43