Luis Valencia
Luis Valencia

Reputation: 33988

How to use a controller for a partial view?

I have the following mockup.

enter image description here

I need that the user profile on the top left is dinamically loaded, so I splitted the navigation.cshtml into two files.

Navigation.cshtml

<nav class="navbar-default navbar-static-side" role="navigation">
    <div class="sidebar-collapse">
        <ul class="nav" id="side-menu">
            <li class="nav-header">
                <!-- Top Navbar -->
                @Html.Partial("_Profile")

            </li>
            <li class="@Html.IsSelected(action: "Index")">
                <a href="@Url.Action("Index", "Home")"><i class="fa fa-laptop"></i> <span class="nav-label">Main page</span> </a>
            </li>
            <li class="@Html.IsSelected(action: "Minor")">
                <a href="@Url.Action("Minor", "Home")"><i class="fa fa-desktop"></i> <span class="nav-label">Minor page</span></a>
            </li>
        </ul>
    </div>
</nav>

and profile.cshtml

<div class="dropdown profile-element">
    <span>
        <img alt="image" class="img-circle" src="~/Images/profile_small.jpg" />
    </span>
    <a data-toggle="dropdown" class="dropdown-toggle" href="#">
        <span class="clear">
            <span class="block m-t-xs">
                <strong class="font-bold">David Williams</strong>
            </span> <span class="text-muted text-xs block">Art Director <b class="caret"></b></span>
        </span>
    </a>
    <ul class="dropdown-menu animated fadeInRight m-t-xs">
        <li><a href="@Url.Action("Profile", "AppViews")">Profile</a></li>
        <li><a href="@Url.Action("Contacts", "AppViews")">Contacts</a></li>
        <li><a href="@Url.Action("Inbox", "Mailbox")">Mailbox</a></li>
        <li class="divider"></li>
        <li><a href="@Url.Action("Login", "Pages")">Logout</a></li>
    </ul>
</div>
<div class="logo-element">
    IN+
</div>

and I have one controller that will return the name of the user.

 public class UserProfileController : Controller
    {
        // GET: UserProfile
        public async Task<ActionResult> GetPropertiesForUser()
        {
            Uri serviceRoot = new Uri(SettingsHelper.AzureAdGraphApiEndPoint);
            var token = await AppToken.GetAppTokenAsync();

            ActiveDirectoryClient adClient = new ActiveDirectoryClient(
             serviceRoot,
             async () => await AppToken.GetAppTokenAsync());
            string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

            Microsoft.Azure.ActiveDirectory.GraphClient.Application app = (Microsoft.Azure.ActiveDirectory.GraphClient.Application)adClient.Applications.Where(
                a => a.AppId == SettingsHelper.ClientId).ExecuteSingleAsync().Result;
            if (app == null)
            {
                throw new ApplicationException("Unable to get a reference to application in Azure AD.");
            }

            string requestUrl = string.Format("https://graph.windows.net/{0}/users/{1}?api-version=1.5", SettingsHelper.Tenant,ClaimsPrincipal.Current.Identities.First().Name);

            HttpClient hc = new HttpClient();
            hc.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
                "Bearer", token);

            HttpResponseMessage hrm = await hc.GetAsync(new Uri(requestUrl));

            if (hrm.IsSuccessStatusCode)
            {
                string jsonresult = await hrm.Content.ReadAsStringAsync();
                return View("GetPropertiesForUser", new UserProfile
                {
                    DisplayName = jsonresult //I am still missing here to get the display name only
                });
            }
            else
            {
                return View();
            }
        }

    }

The thing I dont know how to do

How can I use a controller with a partial view?

UPDATE 1.

I updated the code as suggested by users below:

<nav class="navbar-default navbar-static-side" role="navigation">
    <div class="sidebar-collapse">
        <ul class="nav" id="side-menu">
            <li class="nav-header">
                <!-- Top Navbar -->
          @{ Html.RenderAction("GetPropertiesForUser", "UserProfile"); }
            </li>
            <li class="@Html.IsSelected(action: "Index")">
                <a href="@Url.Action("Index", "Home")"><i class="fa fa-laptop"></i> <span class="nav-label">Main page</span> </a>
            </li>
            <li class="@Html.IsSelected(action: "Minor")">
                <a href="@Url.Action("Minor", "Home")"><i class="fa fa-desktop"></i> <span class="nav-label">Minor page</span></a>
            </li>
        </ul>
    </div>
</nav>


 public class UserProfileController : Controller
    {
        public async Task<ActionResult> GetPropertiesForUser()
        {
            Uri serviceRoot = new Uri(SettingsHelper.AzureAdGraphApiEndPoint);
            var token = await AppToken.GetAppTokenAsync();

            ActiveDirectoryClient adClient = new ActiveDirectoryClient(
             serviceRoot,
             async () => await AppToken.GetAppTokenAsync());
            string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

            Microsoft.Azure.ActiveDirectory.GraphClient.Application app = (Microsoft.Azure.ActiveDirectory.GraphClient.Application)adClient.Applications.Where(
                a => a.AppId == SettingsHelper.ClientId).ExecuteSingleAsync().Result;
            if (app == null)
            {
                throw new ApplicationException("Unable to get a reference to application in Azure AD.");
            }

            string requestUrl = string.Format("https://graph.windows.net/{0}/users/{1}?api-version=1.5", SettingsHelper.Tenant,ClaimsPrincipal.Current.Identities.First().Name);

            HttpClient hc = new HttpClient();
            hc.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
                "Bearer", token);

            HttpResponseMessage hrm = await hc.GetAsync(new Uri(requestUrl));

            if (hrm.IsSuccessStatusCode)
            {
                UserProfile up = JsonConvert.DeserializeObject<UserProfile>(await hrm.Content.ReadAsStringAsync());
                return PartialView(up);
                //return View("GetPropertiesForUser", new UserProfile
                //{
                //    DisplayName = up.displayName() //I am still missing here to get the display name only
                //});
            }
            else
            {
                return View();
            }
        }

    }

@model Inspinia_MVC5_Capatech.Models.UserProfile
<div class="dropdown profile-element">
    <span>
        <img a...

However I get this error: http://screencast.com/t/8VKj4Hwg

The partial view name is called _Profile.cshtml

Upvotes: 1

Views: 3355

Answers (2)

Guillermo Vasconcelos
Guillermo Vasconcelos

Reputation: 1701

Instead of using Html.Partial you can use Html.Action or Html.RenderAction, pointing to the controller action. Somethign like:

        <li class="nav-header">
            <!-- Top Navbar -->
            @Html.Action("GetPropertiesForUser")

Make sure to return PartialView() from the Controller instead of View().

Regarding the error in Update 1, you need to use the naming convention (shared name between Action and View) or indicate the name of the view.
In your case I think you need to replace the return to something like:

return PartialView("_Profile");

Upvotes: 2

Win
Win

Reputation: 62260

Actually you need a ChildAction with Partial View since you want GetPropertiesForUser action to use profile.cshtml view.

public class UserProfileController : Controller
{
   [ChildActionOnly]
   public ActionResult GetPropertiesForUser()
   {
      // ...
     return PartialView(...);
   }
}

Usage

@Html.Action("GetPropertiesForUser", "UserProfile")

OR

@{ Html.RenderAction("GetPropertiesForUser", "UserProfile"); }

Upvotes: 4

Related Questions