Control view component visibility in the ASP.NET MVC 5 controller

Asked

Viewed 1,697 times

8

I am refactoring a project in ASP.NET MVC 5, implementing some good practices and researching, it was mentioned that the use of if na view(Razor) is not the best practice, only that I use it to show or hide some components(fields) according to the current user’s permission, I am searching how to limit this by the controller so that the view rendering is performed, but I am not able to find a way to do this (I don’t even know if it is possible really), I will put an example of a current view code:

    @if ((bool)Session["TipoChamadoVisivel"])
    {
        <div class="form-group">
            @Html.LabelFor(model => model.TipoChamado, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.RadioButtonFor(model => model.TipoChamado, "1")<label>&nbsp;Totvs RM</label>
                <label>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</label>
                @Html.RadioButtonFor(model => model.TipoChamado, "2")<label>&nbsp;Outros</label>
                <p>@Html.ValidationMessageFor(model => model.TipoChamado, "", new { @class = "text-danger" })</p>
            </div>

        </div>
    }

    @if ((bool)Session["ObraVisivel"])
    {
        <div class="form-group">
            @Html.Label("Obra Destino", new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.DropDownListFor(m => m.ObraDestino, new SelectList(new prj_chamadosBRA.Repositories.ObraDAO().BuscarObrasPorUsuario(ViewBag.UserId), "IDO", "Descricao"), "-- Selecione a Obra --", new { @class = "form-control" })
                @Html.ValidationMessageFor(m => m.ObraDestino, "", new { @class = "text-danger" })
            </div>
        </div>
    }
    @if ((bool)Session["SetorVisivel"])
    {
        if (Session["PerfilUsuario"].ToString() != "1")
        {
            <div class="form-group">
                @Html.Label("Setor Destino", new { @class = "col-md-2 control-label" })
                <div class="col-md-10">
                    @Html.DropDownListFor(m => m.SetorDestino, new SelectList(new prj_chamadosBRA.Repositories.SetorDAO().BuscarSetoresPorObra(ViewBag.SetorDestino), "Id", "Nome"), new { @class = "form-control" })
                    @Html.ValidationMessageFor(m => m.SetorDestino, "", new { @class = "text-danger validacaoSetor" })
                </div>
            </div>
        }
        else
        {
            <div class="form-group">
                @Html.Label("Setor Destino", new { @class = "col-md-2 control-label" })
                <div class="col-md-10">
                    @Html.DropDownListFor(m => m.SetorDestino, new SelectList(string.Empty, "Id", "Nome"), "-- Selecione o Setor --", new { @class = "form-control" })
                    @Html.ValidationMessageFor(m => m.SetorDestino, "", new { @class = "text-danger" })
                </div>
            </div>
        }
    }

    @if ((bool)Session["SelecionarResponsavelAbertura"])
    {
        <div class="panel panel-default">
            <div class="panel-heading">
                <h4 class="panel-title">
                    <a data-toggle="collapse" data-parent="#accordion" href="#pnlResponsavelAbertura">Abrir chamado em nome de outro usuário?</a>
                </h4>
            </div>
            <div id="pnlResponsavelAbertura" class="panel-collapse collapse">
                <div class="panel-body">
                    @if (Session["PerfilUsuario"].ToString() != "1" && Session["PerfilUsuario"].ToString() != "4")
                    {
                        <div class="form-group">
                            @Html.Label("Selecione Usuario:", new { @class = "col-md-2 control-label" })
                            <div class="col-md-10">
                                @Html.DropDownListFor(m => m.ResponsavelAberturaChamado, new SelectList(new prj_chamadosBRA.Repositories.ApplicationUserDAO().retornarUsuariosObra(ViewBag.SetorDestino), "Id", "Nome"), "-- Selecione o usuário --", new { @class = "form-control" })
                                @Html.ValidationMessageFor(m => m.ResponsavelAberturaChamado, "", new { @class = "text-danger" })
                            </div>
                        </div>
                    }
                    else
                    {
                        <div class="form-group">
                            @Html.Label("Selecione Usuario:", new { @class = "col-md-2 control-label" })
                            <div class="col-md-10">
                                @Html.DropDownListFor(m => m.ResponsavelAberturaChamado, new SelectList(string.Empty, "Id", "Nome"), "-- Selecione a obra primeiro --", new { @class = "form-control" })
                                @Html.ValidationMessageFor(m => m.ResponsavelAberturaChamado, "", new { @class = "text-danger" })
                            </div>
                        </div>
                    }
                </div>
            </div>
        </div>
    }

2 answers

4

Using session variables in this way is quite dangerous:

@if ((bool)Session["TipoChamadoVisivel"]) { ... }

Because you don’t test the existence of this content before using it.

Also, this way of using causes some visual pollution. The best way to solve is to encapsulate the content through Partials, by testing first whether the session variable exists. For example, this code fragment:

@if ((bool)Session["TipoChamadoVisivel"])
{
    <div class="form-group">
        @Html.LabelFor(model => model.TipoChamado, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.RadioButtonFor(model => model.TipoChamado, "1")<label>&nbsp;Totvs RM</label>
            <label>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</label>
            @Html.RadioButtonFor(model => model.TipoChamado, "2")<label>&nbsp;Outros</label>
            <p>@Html.ValidationMessageFor(model => model.TipoChamado, "", new { @class = "text-danger" })</p>
        </div>

    </div>
}

Can be encapsulated inside a Partial so-called:

@Html.Partial("_TipoChamado", Model).If(Session["TipoChamadoVisivel"] != null)

This If is an extension that can be implemented as follows:

public static class HtmlHelperExtensions
{

    /// <summary>
    /// Método de extensão para avaliar condições na View.
    /// </summary>
    /// <param name="valor"></param>
    /// <param name="avaliacao"></param>
    /// <returns></returns>
    public static IHtmlString If(this IHtmlString valor, bool avaliacao)
    {
        return avaliacao ? valor : MvcHtmlString.Empty;
    }

}

Another tip is to register the Namespace of extensions in web.config of the directory Views:

<configuration>
  ...
  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
    <!--pages pageBaseType="ServiceStack.Razor.ViewPage"-->
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="System" />
        <add namespace="MeuProjeto" />
        <add namespace="MeuProjeto.Extensions" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
  ...
</configuration>

To Partial would look like this:

@if ((bool)Session["TipoChamadoVisivel"]) // Agora você sabe que a variável existe, e pode usar sem problemas.
{
    <div class="form-group">
        @Html.LabelFor(model => model.TipoChamado, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.RadioButtonFor(model => model.TipoChamado, "1")<label>&nbsp;Totvs RM</label>
            <label>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</label>
            @Html.RadioButtonFor(model => model.TipoChamado, "2")<label>&nbsp;Outros</label>
            <p>@Html.ValidationMessageFor(model => model.TipoChamado, "", new { @class = "text-danger" })</p>
        </div>

    </div>
}

4


Visualization control are the responsibility of the same view. The controller has another responsibility within the MVC, which is to receive, interpret and direct user requests by responding to and triggering controllers for each type of operation.

There is nothing wrong with using the Razor IF’s inside the view, if you create a project from scratch with the microsoft login template itself you will see that they use ifs to show the login or logout in the upper corner according to model status.

Really I think the danger here is you access and make direct use of your session to make these validations.

Maybe it would be better inside your Model you have a struct of views and then yes make use of it in the view.

And yes in your controller you do the manipulation of what types of views this model has and then yes manipulate the view in the view.

Another tip is to make use of Viewdata which is exactly a transient data type that lasts only between a request and the view rendering.

If you want to improve the code and make it cleaner you can apply this along with the partial rendering pattern Partials

And putting the two together Could be like this

@if((bool)ViewData["MostrarSecao1"]) { @{Html.RenderPartial("secao1", Model);} }
@if((bool)ViewData["MostrarSecao2")) { @{Html.RenderPartial("secao2", Model);} }

These Viewdata are filled in your controller.

ViewData["MostrarSecao1"] = //condição para mostrar a seção 1;
ViewData["MostrarSecao2"] = //condição para mostrar a seção 2;

And your partials can be anywhere in the project (within clear views) and in them you can have only your code without ifs. For example

<div class="form-group">
            @Html.Label("Obra Destino", new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.DropDownListFor(m => m.ObraDestino, new SelectList(new prj_chamadosBRA.Repositories.ObraDAO().BuscarObrasPorUsuario(ViewBag.UserId), "IDO", "Descricao"), "-- Selecione a Obra --", new { @class = "form-control" })
                @Html.ValidationMessageFor(m => m.ObraDestino, "", new { @class = "text-danger" })
            </div>
        </div>

That code of yours would be inside the partial secao1.cshtml

Browser other questions tagged

You are not signed in. Login or sign up in order to post.