Reputation: 1772
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
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:
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:
@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:
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:
Upvotes: 0