Prageeth Liyanage
Prageeth Liyanage

Reputation: 1772

How to download the coverted doc file from viewcomponent?

I have a view component which do file upload.

  public async Task<IViewComponentResult> InvokeAsync (ToolModel model)
    {
        if (!ModelState.IsValid)
        {
            return View();
        }

        if (model.FileUpload != null)
        {
            //SaveFullImage(strm, model.FileUpload.FileName);
            #region Uploading photo]
            string wwwPath = string.Empty;
            string fromFileName = string.Empty;
            string toFileName = string.Empty;
            string fromFilePath = string.Empty;
            string toFilePath = string.Empty;
            if (model.FileUpload.Length > 0)
            {
                wwwPath = this.env.WebRootPath;
                string guiD = Guid.NewGuid().ToString();
                fromFileName = string.Format("{0}-{1}.{2}", DateTime.Now.ToString("yyyy-MM-dd"), guiD, model.FromFileType);
                fromFilePath = string.Format("{0}\\file-uploads\\{1}", wwwPath, fromFileName);

                toFileName = string.Format("{0}-{1}.{2}", DateTime.Now.ToString("yyyy-MM-dd"), guiD, model.ToFileType);
                toFilePath = string.Format("{0}\\file-convertions\\{1}", wwwPath, toFileName);


                try
                {
                    using (Stream fileStream = new FileStream(fromFilePath, FileMode.Create))
                    {
                        await model.FileUpload.CopyToAsync(fileStream);
                        fileStream.Close();
                    }
                }
                catch (Exception)
                {

                    throw;
                }
            }

            var exists = System.IO.File.Exists(fromFilePath);
            if (exists)
            {
                model.FromFileUploadedURL = fromFilePath;
                model.ToFileConvertedURL = toFilePath;
                model.IsSuccessFullFileUpload = true;
            }
            else
                model.IsSuccessFullFileUpload = false;
            #endregion

            if (model.IsSuccessFullFileUpload)
            {
                FileConverters.ConvertPDFtoWord(model.FromFileUploadedURL, model.ToFileConvertedURL);
                // Download Word file
                //byte[] fileBytes = System.IO.File.ReadAllBytes(model.ToFileConvertedURL);
                //return File(fileBytes, "application/force-download", "ddd");
            }
        }

        return await Task.FromResult((IViewComponentResult)View(FullPathsOfViews.FileUpload, model));
    }

At the end of the line

  FileConverters.ConvertPDFtoWord(model.FromFileUploadedURL, model.ToFileConvertedURL);

After this I want to allow the converted doc file to downloaded back to user's PC. But below lines not work inside view component

  byte[] fileBytes = System.IO.File.ReadAllBytes(model.ToFileConvertedURL);
                return File(fileBytes, "application/force-download", "ddd");

Here is the action result from controller class.

public async Task<IActionResult> Index(ToolModel model)

How to do that? Because viewcomponent fired finally and it not comes back to the controller.

In Index.cshtml I added following code

@await Component.InvokeAsync("FileUpload",Model)

Below is my viewcomponent

<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="FileUpload" accept="@Model.FileUploadFileFormats" /></div>
    <br />
</div>
<br />
<input asp-action="Index" type="submit" value="Upload" class="btn btn-primary" />
<input asp-action="Clear" type="submit" value="Clear" class="btn btn-outline-primary" />
<br />

<canvas id="pdfViewer" style='width:350px;height:auto'></canvas>
</form>

Upvotes: 0

Views: 388

Answers (1)

Md Farid Uddin Kiron
Md Farid Uddin Kiron

Reputation: 22409

How to do that? Because viewcomponent fired finally and it not comes back to the controller.

I think you are still confused about view component features. We supposed not to do anything within InvokeAsync method. It will just act as and place holder what really a view component is. Rather we would be writing our conditional or any business logic either in viewcomponent caller controller or within viewcomponent.cshtml file but not InvokeAsync because it will beyond its scope. Even if we have written something within that's acually viewComponent developed for.

How to download the coverted doc file from viewcomponent?

Instead of writting any business logic for downloading converted word file within view component, you ought to convert pdf to word file and save that in directory. Finally get the converted word file and pass it to your viewcomponent model.

When your model value passed back to your viewcomponent.cshtml now you can set downloading link or file name which will call the download controller. This would be the ideal scenario and this should be.

Let's take a look how we can do that in action:

Assuming we have below component for uploading .pdf file and after accomplishing all conversion process want .docx or downloadable link for word file as following:

enter image description here

enter image description here

Let's move towards the implementation:

Component Model:

public class DownloadComponentModel
    {
        public IFormFile? FileUpload { get; set; } = null;
        public string? FileUploadFileFormats { get; set; } = "application/pdf";
        public string? FileExtentionMessage { get; set; } = string.Empty;
        public string? DownloadLink { get; set; } = string.Empty;
    }

Note: I as using DownloadLink where I would pass converted file name.

Component:

    [ViewComponent(Name = "FileDownloader")]
    public class FileDownloaderViewComponent : ViewComponent
    {

        public IViewComponentResult Invoke(DownloadComponentModel fileDownloadViewModel)
        {

            return View("FileDownloader", fileDownloadViewModel);
        }
    }

View Component cshtml:

enter image description here

@model DotNet6MVCWebApp.Models.DownloadComponentModel
<form asp-controller="FileUploadViewComponent" asp-action="UploadDownload" enctype="multipart/form-data">

    <div class="card card-body">
        <strong>Select PDF file to convert</strong> <div id="chooseFile"><input type="file" asp-for="FileUpload" accept="@Model.FileUploadFileFormats" /></div>
        <br />
    </div>
    <br />
    <input asp-action="UploadDownload" type="submit" value="Upload" class="btn btn-primary" />
    <input asp-action="Clear" type="submit" value="Clear" class="btn btn-outline-primary" />

   
    <br />
    @{
        if (Model.DownloadLink == string.Empty || Model.FileExtentionMessage == string.Empty)
        {

        }
        else
        {
            <label asp-for="FileExtentionMessage" class="control-label" style="color:red">Note: @Model.FileExtentionMessage</label>
            <br />
            <a asp-action="DownloadPdfFile" class="btn btn-warning" asp-route-fileName="@Model.DownloadLink">Download File</a>
        }
    }
</form>

Note: Write your business logic whatever in mind here. But you are doing instead which made the scenario complicated. Regarding the logic I have written is, at the beginning we woundn't have any file link so I am checking that and once we have file link and extension details only then showing the details link for download.

Download Controller Action:

public async Task<IActionResult> UploadDownload(DownloadComponentModel FileName)
        {
            var downloadableFileDetails = new DownloadComponentModel();
            if (FileName.FileUpload == null)
            {
                return View(downloadableFileDetails);
            }
            else
            {
                string checkFileExtension = System.IO.Path.GetExtension(FileName.FileUpload.FileName);

                string[] expectedFile = { ".pdf" };

                if (expectedFile.Contains(checkFileExtension))
                {
                    //Save file into directory
                    var path = Path.Combine(_environment.WebRootPath, "ViewComponentUpload", FileName.FileUpload.FileName);
                    using (FileStream stream = new FileStream(path, FileMode.Create))
                    {
                        await FileName.FileUpload.CopyToAsync(stream);
                        stream.Close();
                    }
                    //Covert your file from PDF to Word file and get the converted file name
                    //I am not writing convert login here just getting the file name of converted file
                    downloadableFileDetails.FileExtentionMessage = checkFileExtension;
                    downloadableFileDetails.DownloadLink = FileName.FileUpload.FileName;//Pass converted file name here.
                }
                else
                {

                    downloadableFileDetails.FileExtentionMessage = "Invalid file type";
                    downloadableFileDetails.DownloadLink = "Sorry no download link available!";
                }
            }
           
            return View(downloadableFileDetails);
        }

Download View To Invoke View Component:

@model DotNet6MVCWebApp.Models.DownloadComponentModel
<div>

    @await Component.InvokeAsync("FileDownloader",Model)
</div>

Download Docs File Controller Action:

enter image description here

public async Task<IActionResult> DownloadPdfFile(string fileName)
        {
            var readFileFromThisPath = Path.GetFullPath("./wwwroot/ViewComponentUpload/" + fileName);
            byte[] fileBytes = System.IO.File.ReadAllBytes(readFileFromThisPath);
            return File(fileBytes, "application/force-download", fileName);
           
        }

Output:

enter image description here

Upvotes: 0

Related Questions