locked
Very basic showing cookie/ get data from db, in ASP.net MVC Core partial view RRS feed

  • Question

  • User576772373 posted

    I'm sure it is basic, I'm trying to learn MVC core (v 3.1) after working in ASP.NET forms for many years and it is a bit of a steep learning curve, any help would be much appreciated.

    I set up a basic website, for each registered user, I would like to have a few profiles (like netflix).

    I am stuck at something very basic: how to access database (or even a cookie) from a partial view page.

    In the Controllers folder, I now have this page GetUserProfileExtension.cs (which doesn't work):

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Http;
    
    namespace myMVC.Controllers
    {
        public  class GetUserProfileExtension : Controller
        {
             public static string GetUserProfile()
            {
                var Name = HttpContext.Request.Cookies["SelectedUser"];
                return Name;
            }
        }
    }
    

    The error is: HttpContext is underlined and it says "object reference is required"

    In my _LoginPartial.cshtml (which is rendered in the _Layout.cshtml - all default at this stage) I just at this stage want to see a cookie value (which I set up when a user is created then creates a profile/selects if more than one)

    @using Microsoft.AspNetCore.Identity
    @inject SignInManager<IdentityUser> SignInManager
    @inject UserManager<IdentityUser> UserManager
    
    
    <h1>@myMVC.Controllers.GetUserProfileExtension.GetUserProfile()</h1>

    Ideally, at first I would just love to see the cookie value rendered in partial view. But the next step. I have a ProfilesModels table in the database - how do I extract a row of data from that table (based on the ID in the cookie) and show it in the partial.

    I know this is very basic - in ASP.NET forms I would have had this in under 3 minutes, but after googling and reading manuals for 3-4 days I'm getting desperate. Thank you in advance

    Sunday, April 26, 2020 7:56 AM

Answers

  • User1686398519 posted

    Hi, alexi

    First of all, because "HttpContext" is a non-static method, but you write it below the static method, so you will get an error.

    Secondly, I made an example for your needs.

    More details, you could refer to below code:

    GetUserProfileExtension.cs

     public class GetUserProfileExtension : Controller
    
        {
    
            private theManagerContext _context;
    
     
    
            public GetUserProfileExtension(theManagerContext context)
    
            {
    
                _context = context;
    
            }
    
            public IActionResult Index()
    
            {
    
                //Assuming cookies are assigned
    
                SetCookies("SelectedUser", "test1");
    
     
    
                //call GetUserProfile() and assign
    
                string name = GetUserProfile();
    
     
    
                //Use ViewData to pass the value of name
    
                ViewData["name"] = name;
    
                return View(_context.ProfilesModels.Where(u => u.UserName == name).ToList());
    
            }
    
            public string GetUserProfile()
    
            {
    
                var Name = HttpContext.Request.Cookies["SelectedUser"];
    
                return Name;
    
            }
    
            //Simulation setting cookies
    
            protected void SetCookies(string key, string value, int minutes = 30)
    
            {
    
                HttpContext.Response.Cookies.Append(key, value, new CookieOptions
    
                {
    
                    Expires = DateTime.Now.AddMinutes(minutes)
    
                });
    
            }
    
     
    
    }

    _LoginPartial.cshtml

    <h1>@ViewData["name"]</h1>

    _Layout.cshtml

    <ul class="nav navbar-nav navbar-right">
    
                            <li>
    
                                @{
    
                                    await Html.RenderPartialAsync("_LoginPartial");
    
                                }
    
                            </li>
    
                        </ul>

    Index.cshtml

    @{
    
        ViewData["Title"] = "Index";
    
    }
    
     
    
    <h1>Index</h1>
    
    @foreach (var item in Model)
    
    {
    
        @Html.DisplayName("UserId")
    
        @Html.TextBox("UserId",item.UserId)
    
        @Html.DisplayName("UserName")
    
        @Html.TextBox("UserName", item.UserName)
    
        @Html.DisplayName("UserPhone")
    
        @Html.TextBox("UserPhone", item.UserPhone)
    
    }

    ProfilesModels.cs

    public class ProfilesModels
    
        {
    
            [Key]
    
            public string UserId { get; set; }
    
            public string UserName { get; set; }
    
            public string UserPhone { get; set; }
    
        }

    Remarks: For the connection of the database in core, you can refer to the link.

    Here is the result:

     

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, April 27, 2020 7:28 AM
  • User576772373 posted

    Thank you very much for your help again. I used your code but I think it works better with ViewComponent than with partial view - I followed some of the code here if anyone is interested.

    https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.1

    Thank you again YiHuiSun for showing me the way and spending time on this, much appreciated!!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, April 28, 2020 3:04 AM

All replies

  • User475983607 posted

    ASP.NET Core uses dependency to access Session.  The docs cover the configuration and access details.

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-3.1

    I would use claims to store user profile information.  It's pretty simple to assign a claim to a user.

    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
        private readonly UserManager<IdentityUser> _userManager;
        public IndexModel(ILogger<IndexModel> logger, UserManager<IdentityUser> userManager)
        {
            _logger = logger;
            _userManager = userManager;
    
        }
    
        public async Task OnGetAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("profile", "My Profile"));
        }
    }

    The user claims are associated the User when the user logs in and it's pretty simple to get the claims

    public async Task OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        IList<System.Security.Claims.Claim> claims = await _userManager.GetClaimsAsync(user);
    
    }

    You'll always want to check if the Profile claim value exists before assignment.  Otherwise, you'll end up with duplicate Profile claim values.   

    Sunday, April 26, 2020 12:26 PM
  • User-474980206 posted

    your not understanding the MVC pattern. The views do not call code in the controller. the request is maped to a controller action. This action processes the request and builds a model to pass to the view.

    razor views are a template engine, not a control tree like in webforms. in mvc all the page logic goes in the controller action, and the view is like the render. MVC is an common pattern used in building web sites (webforms is based on a component pattern). MVC lends itself to writing unit tests for controller actions.

    so to your question, the view should not access a database, nor should it have cookie logic. this shock all be done in the controller action or by middleware. you just pass a model to the view, and it should render the html. data fetching, cookie reading, redirect logic all belongs in the controller action.

    if you are uncomfortable learning the MVC pattern, then you might want to switch to razor pages, which is more akin to webforms than MVC. it is still a template, but the template contains the processing logic, rather than it being separate.

     

     

    Sunday, April 26, 2020 3:43 PM
  • User1686398519 posted

    Hi, alexi

    First of all, because "HttpContext" is a non-static method, but you write it below the static method, so you will get an error.

    Secondly, I made an example for your needs.

    More details, you could refer to below code:

    GetUserProfileExtension.cs

     public class GetUserProfileExtension : Controller
    
        {
    
            private theManagerContext _context;
    
     
    
            public GetUserProfileExtension(theManagerContext context)
    
            {
    
                _context = context;
    
            }
    
            public IActionResult Index()
    
            {
    
                //Assuming cookies are assigned
    
                SetCookies("SelectedUser", "test1");
    
     
    
                //call GetUserProfile() and assign
    
                string name = GetUserProfile();
    
     
    
                //Use ViewData to pass the value of name
    
                ViewData["name"] = name;
    
                return View(_context.ProfilesModels.Where(u => u.UserName == name).ToList());
    
            }
    
            public string GetUserProfile()
    
            {
    
                var Name = HttpContext.Request.Cookies["SelectedUser"];
    
                return Name;
    
            }
    
            //Simulation setting cookies
    
            protected void SetCookies(string key, string value, int minutes = 30)
    
            {
    
                HttpContext.Response.Cookies.Append(key, value, new CookieOptions
    
                {
    
                    Expires = DateTime.Now.AddMinutes(minutes)
    
                });
    
            }
    
     
    
    }

    _LoginPartial.cshtml

    <h1>@ViewData["name"]</h1>

    _Layout.cshtml

    <ul class="nav navbar-nav navbar-right">
    
                            <li>
    
                                @{
    
                                    await Html.RenderPartialAsync("_LoginPartial");
    
                                }
    
                            </li>
    
                        </ul>

    Index.cshtml

    @{
    
        ViewData["Title"] = "Index";
    
    }
    
     
    
    <h1>Index</h1>
    
    @foreach (var item in Model)
    
    {
    
        @Html.DisplayName("UserId")
    
        @Html.TextBox("UserId",item.UserId)
    
        @Html.DisplayName("UserName")
    
        @Html.TextBox("UserName", item.UserName)
    
        @Html.DisplayName("UserPhone")
    
        @Html.TextBox("UserPhone", item.UserPhone)
    
    }

    ProfilesModels.cs

    public class ProfilesModels
    
        {
    
            [Key]
    
            public string UserId { get; set; }
    
            public string UserName { get; set; }
    
            public string UserPhone { get; set; }
    
        }

    Remarks: For the connection of the database in core, you can refer to the link.

    Here is the result:

     

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, April 27, 2020 7:28 AM
  • User576772373 posted

    Hi YihuiSun,

    Thank you very much for your detailed reply, I very highly appreciate it.

    I've copied your code (adjusted the dbcontext name), but at this stage the h1 tag is rendered empty {i basically need to see it on every page/view in the web app}. What's more the SelectedUser cookie is given the value that's set up elsewhere, so it is not set by the SetCookies() function you wrote.

    I have a feeling that the Index action of the GetUserProfile controller is not invoked in the partial view, but I'm not quite sure how to do it. I feel like it is almost there but something small is missing. 

    Thank you so very much for the obvious time you spent on this!

    Alexi

    Monday, April 27, 2020 3:11 PM
  • User576772373 posted

    Thank you very much for your help again. I used your code but I think it works better with ViewComponent than with partial view - I followed some of the code here if anyone is interested.

    https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.1

    Thank you again YiHuiSun for showing me the way and spending time on this, much appreciated!!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, April 28, 2020 3:04 AM