Question

I have an asp.net-mvc website where up until now there have been no entitlements as its been open to everyone. Many of the pages are detailed forms with textboxes, select dropdowns, etc

I now need to change this to make many of the existing pages "entitled" so only certain people have edit capability and everyone else sees a read only page. I am trying to figure out if I should

  1. Create a seperate view for everyone one of my existing views with forms that is just read only html on a page and redirect based on entitlements on the server side, something like

    public ActionResult OrderView()
    {
         var isEntitled = Model.IsEntitled()
         if (isEntitled)
         { 
              return("OrderEditableView", GetViewModel()); 
         }
         else 
         {
             return("OrderReadOnlyView", GetViewModel());  
         }
    

    }

or

  1. Reuse the same view and simply disable or hide the "Save" button on the screen.

on my view have

     <% if (Model.IsEntitled) { %>
           <button id="saveButton">Save Changes</button>
     <% } %>

The second option would be much quicker to implement but would be a little weird because it would look like you could edit all of the fields but just dont' see (or see a disabled) Save button on the form.

The first option seems cleaner but I would have to go and create a new view for everyone of my screens and that seems like a lot of work (over 100 views currently)

This seems like a common situation so I wanted to see if there was a best practice on dealing with this situation. Obviously I am looking for a solution given the current situation that I am in but I would also be interested if there were patterns or solution that would be considered best practice or recommended if I was starting from scratch.

Was it helpful?

Solution

I would go for creating a separate partial/full views for both.

Reasons:
easy to change and maintain
validation code only in editable part
clear separation of concerns
cleaner code
may be we can reuse some of the code by abstracting/separating similar code to re usable partial views
easy control over access

Also, in real world we balance among budget,time and effort. so considering that I may use mix of these depending upon the situation.

OTHER TIPS

I'd go for the second options with a single view for both writable and readonly forms.

For the visual side, I'd implement a few things in addition to hiding the Save button:

  • Set the input fields to readonly. You can easily do this with client side Javascript.

  • Change the colors (and possibly other attributes) of the input fields to emphasize that they are readonly (e.g. remove the borders). This can be easily achieved by a style sheet and a single additional class name in the form tag.

The authorization on the server side is simple as well. Just annotate the action accordingly.

It could look like this (simplified, using Razor and jQuery):

View:

@using (Html.BeginForm("AddressController", "SaveChanges", FormMethod.Post,
        new { @class = Model.IsEntitled ? "regular" : "readonly"}))
{
   <p>
     @Html.TextboxFor(model => model.Name)
   </p>
   <p>
     @Html.TextboxFor(model => model.Address)
   </p>
   @if (Model.IsEntitled) {
     <p>
       <button id="saveButton">Save Changes</button>
     </p>
   }
}

<script type="text/javascript">
  $( document ).ready(function() {
     $('form.readonly input').attr("readonly", true);
  });
</script>

Controller:

public class AddressController : Controller {

    [Authorize(Roles = "xyz")]
    [HttpPost]
    public ActionResult SaveChanges(Address address) {
        ...
    }
}

CSS:

.readonly input {
    border: none;
}

an option is to do the switch in the view..

<% if (Model.IsEntitled) 
{ 
    Html.Partial("OrderEditablePartialView", Model)
}
else 
{
    Html.Partial("OrderReadOnlyPartialView", Model)
}
%>

another option could be to create custom Html helpers to render the elements as editable or readonly, which would give you some flexibily on how you handled each element.

crude example:

public static MvcHtmlString FormTextBox(this HtmlHelper helper, string name, string text, bool editable)
        {
            return
                new MvcHtmlString(
                    String.Format(
                        editable
                            ? "<input type='text' id='{0}' name='{0}' value='{1}'>"
                            : "<label for='{0}'>{1}</label>",
                            name, text));
        }

The quickest solution would be some javascript that disables all input elements on pages where the user isn't entitled. How to implement this is up to you, it depends on how your views and models are structured.

This way you can reuse the edit-views without even having to edit them, but depending on the kind of user you have you can expect "site not working" calls when your forms appear disabled.

patterns or solution that would be considered best practice or recommended if I was starting from scratch.

The proper way to go would be DisplayTemplates and EditorTemplates with proper viewmodels, but from your "create a new view for everyone of my screens and that seems like a lot of work" comment I gather you're not interested in that.

So I'd go with the former. Please make sure you check the permissions in the [HttpPost] action methods, as malicious users can easily re-enable the form and post it anyway.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top