Search code examples
asp.net-coreasp.net-mvc-partialviewasp.net-core-viewcomponent

When to use partial view and ViewComponent?


I am beginner for asp.net core. I am building file conversion website. PNG to JPG, PDF to Word etc.. In there I amusing fileuplaod control to upload content for the conversation. Instead using same control on every view I thought put this control in one class and call them. When I search internet I found following two methods

  1. ViewComponent method
  2. Partial view method

Now I am confused what to use? Note that on page to page upload file type will be differ. on JPG to PNG converter page I have to restrict the fileuplaod control to only use JPEG images. So I want to pass some parameters to this common control and after Upload process done, I want to call back to the calling page to do specific convertions.

So following things I have implemented so far

I followed Viewcomponentmethod

@model BassModel
@*<form asp-controller="FileUploadViewComponent" enctype="multipart/form-data">*@
    <div class="card card-body">
        <strong>Select PDF file to convert</strong> <div id="chooseFile"><input type="file" asp-for="@Model" accept="image/*" /></div>
        <br />
    </div>
    <br />
    <input asp-action="Index" type="button" value="Upload" class="btn btn-primary" />
    <input asp-action="Clear" type="submit" value="Clear" class="btn btn-outline-primary" />
    <br />
@*</form>*@

On PDF to word view

<form asp-controller="FileUploadController">
    @section _FileUpload{
        @await Component.InvokeAsync("_FileUpload", Model)
    }
</form>

On _layout page

<div class="container">
    <div class="row">
        <div class="col-md-7">
            <div class="container background_color_white">
                <main role="main" class="pb-3">
                    @RenderBody()
                </main>
            </div>
            <br />
            <div class="container background_color_white">
                @RenderSection("_FileUpload",false)
            </div>
        </div>
</div>

So far I done this. Erros are coming. But before I go further, I want to ensure what I do is right. Am I going in the right direction?


Solution

  • Instead using same control on every view I thought put this control in one class and call them. When I search internet I found following two methods

    ViewComponent method

    Partial view method

    Now I am confused what to use?

    Well, based on your scenario, let's have a look in which context we should better use partial views

    1. If you want to split your larger mark up files
    2. You want to reduce redundant file accross your projct.

    Note: As per Microsoft recomendation, we shouldn't use a partial view where complex rendering logic or code execution is required to render the markup. Instead of a partial view, use a view component. You could check here.

    However, based on scenario it has appeared that you don't want to use same control everywhere and you have complex logical implementation within your project, here we goes the crucial reasons why we should use View components

    Although both partial views and View components are similar but View component is more robust and can handle complex requiremnet as it depend on the data passed while calling which completely comply with your requirement.

    Demo implementation of your scenario:

    It would be nicer if could share your error details what you are up to now. Nonetheless, Based on your shared snippet I have tried to simulate a quick demo for you based on the scenario:

    Component Model:

    public class UploadComponentModel
        {
            public IFormFile? MyUploadedFile { get; set; } = null;
            public string? FileExtntionName { get; set; } = string.Empty;
            public string? UploadedFileName { get; set; } = string.Empty;
        }
    

    View Component Class & Directory:

        [ViewComponent(Name = "FileUploader")]
        public class FileUploaderViewComponent : ViewComponent
        {
    
            public IViewComponentResult Invoke(UploadComponentModel filUploadViewModel)
            {
                return View("FileUploader", filUploadViewModel);
            }
        }
    

    enter image description here

    View Component cshtml in Shared Folder:

    @model DotNet6MVCWebApp.Models.UploadComponentModel
    <div class="col-sm-4">
        <div class="card" style="width: 18rem; margin-bottom:20px;box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;">
            <div class="card-body">
                <form asp-controller="FileUploadViewComponent" asp-action="Index" enctype="multipart/form-data">
                    <div class="card card-body">
                        <strong>Select PDF file to convert</strong> <div id="chooseFile"><input type="file" asp-for="MyUploadedFile" accept="image/*" /></div>
                        <br />
                    </div>
                    <br />
                    <input type="submit" value="Upload" class="btn btn-primary" />
                    <input asp-action="Clear" type="submit" value="Clear" class="btn btn-outline-primary" />
                    <br />
                    <label asp-for="FileExtntionName" class="control-label">@Model.FileExtntionName</label>
                    <br />
                    <label asp-for="UploadedFileName" class="control-label">@Model.UploadedFileName</label>
                </form>
            </div>
        </div>
    
    </div>
    

    enter image description here

    Controller:

    public class FileUploadViewComponentController : Controller
        {
            public IActionResult Index(UploadComponentModel FileName)
            {
    
                var uploadedFileDetails = new UploadComponentModel();
                if (FileName.MyUploadedFile == null)
                {
                    return View(uploadedFileDetails);
                }
                else
                {
                    string checkFileExtension = System.IO.Path.GetExtension(FileName.MyUploadedFile.FileName);
    
                 
                    uploadedFileDetails.MyUploadedFile = FileName.MyUploadedFile;
                    uploadedFileDetails.FileExtntionName = checkFileExtension;
                    uploadedFileDetails.UploadedFileName = FileName.MyUploadedFile.FileName;
                    return View(uploadedFileDetails);
                }
             
            }
        }
    

    Note: Here you can check for your desired file extension and set conditional logic based on your requirement and finally pass the model which will pass through the component.

    Check File Type:

                   string[] expectedFile = { ".pdf", ".png", ".jpeg" };
    
                    if (expectedFile.Contains(checkFileExtension))
                    {
                        uploadedFileDetails.FileExtentionMessage = "Right extension uploaded";
                    }
    

    Invoke View Component In View:

    @model DotNet6MVCWebApp.Models.UploadComponentModel
    <div>
    
        @await Component.InvokeAsync("FileUploader",Model)
    </div>
    

    Note: This is only for demo purpose to assist you to get rid of your error and simulate a imaginary implementation of your scenario.

    Output:

    enter image description here

    Note: If you still interested to know more details on View components you could check our official document here