1
\$\begingroup\$

I have a view which displays a list of items, in each row I'm going to have a link, a link in each row points to different location So base upon a property called CertificationType I have to generate an address, for example if the type equals to 'BirthCertificate' I need to fetch the address from a table called BirthCertificates. So I decided to use a ChildActionOnly action method because in my controller I can easily access to context and fetch the result, That why I didn't use HTML helpers.

View:

foreach(var item in Model)
{
 //...
 <a href="@Html.Action("GetFilePath", new { type = item.CertificateType, certificateFkId = item.CeritificateFk })"></a> 
}

Controller:

public class MainController : Controller
{
 //...
 private readonly IUserCertificateService _certificateService;
 public MainController(IUserCertificateService certificateService)
 {
 _certificateService = certificateService;
 //...
 }
 [ChildActionOnly]
 public ContentResult GetFilePath(CertificateType type, Guid certificateFkId)
 {
 var fileName = "";
 switch (type)
 {
 case CertificateType.Shenasnameh:
 {
 var result = _birthCertificateService.GetBirthCertificateById(certificateFkId);
 fileName = string.Format("/Content/Files/UserDocs/{0}/{1}", result.User.UserName, result.ShenasNamehFileName);
 }
 break;
 //....
 }
 return Content(fileName);
 }
}

It works like a charm. But I wanted to know Is there a better solution?

Any idea?

asked Feb 3, 2016 at 15:41
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

This would appear to be an abuse of child actions. Child Actions are meant to compose smaller items of your interface that you would need to re-use and load up part (albeit a small part) of the MVC pipeline to provide this functionality.

Furthermore, it is giving your Controller responsibility for a unit of work that you may eventually want to reuse elsewhere. Can you really not see a need to work out a full path to a file in the future?

You mention this:

in my controller I can easily access to context and fetch the result, That why I didn't use HTML helpers.

I can understand you not wanting to use HTML Helpers for this, as you need to make a request to a service to find out information about the user and the filename. Fine, but your reference to requiring access to a context, what context? Your service? This doesn't seem to warrant, at least in my eyes, a full controller action.


In my opinion, and this is an opinion-based "how is best to do this" question rather than code review, this method is best suited on your model. Extending your model to have a method that would return a path to the file that you can subsequently output seems like a much more logical place for this type of method. That way, should you need to get a path again in a different controller, you do not need to duplicate code and/or refactor the method into another location at a later date.


Another option would be to construct a ViewModel for each item in your (current) Model, which contains this URL for output. That way you can have a normal method on your controller, and call it whilst constructing the VM in the main Action.


Finally, have your models where the filename is sourced from a different column implement an interface that allows you to get a filename, and fallback to using URL Helpers.

Something as simple as below would suffice:

interface IFileNameProvider
{
 GetFileName();
}

Each implementation would return the filename from its appropriate property as an attempt at model-level (not DB-level) normalisation (of course you could normalise the filename at DB level). That way you can use standard URL helpers after getting your filename from this method, and your username through a similar method.

answered Feb 3, 2016 at 16:23
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.