Save file user side by passing string[] to blazor controller - json

Heres the controller
[ApiController, Route("api/reports"), Authorize]
public class ReportsController : Controller
with the methods
[HttpPost, Route("download")]
public async Task<IActionResult> Download(string[] ids)
{
var cd = new System.Net.Mime.ContentDisposition("attachment") { FileName = "downloads.json" };
Response.Headers.Add("Content-Disposition", cd.ToString());
return Ok(await CreateDocumentsOnIds(ids));
}
[HttpGet, Route("{id}/download")]
public async Task<IActionResult> Download(string id)
{
var cd = new System.Net.Mime.ContentDisposition("attachment") { FileName = $"document_{id}.json" };
Response.Headers.Add("Content-Disposition", cd.ToString());
return Ok(await CreateDocumentOnId(id));
}
Which works fine for one Id:
<table class="table is-fullwidth">
<thead>
<tr>
<th>Link</th>
<th>Dato</th>
</tr>
</thead>
<tbody>
#foreach (var doc in documents)
{
<tr>
<td>#doc.Url</td>
<td>#doc.Updated.ToShortDateString()</td>
<td><a class="button is-link" Color=#Color.Primary href=#($"/api/reports/{doc.Id}/download")>Download</a></td>
</tr>
}
</tbody>
</table>
But I want the possibility to download several documents as one file. And in order for the controller to be able to create this file, it needs ids of the files. Therefore I somehow need to be able to send an object containing these ids to the controller, from the client memory. Is this possible to do with forms?

Related

How do I display a list of audio files from directory to then select one to play?

I'm making a list where files are loaded on the browser. I want to select a file from the list and choose to play it.
Right now, I have a list of the files in the path, and and audio player in the cell on the right that plays the audio of the file that is in the directory.
This displays the list but I can't do anything with it.
<div class="table-wrapper-scroll-y my-custom-scrollbar">
<table class="table table-bordered table-striped mb-0">
<tbody>
#if (filesList != null && filesList.Count > 0)
{
int auF = 0;
#foreach (string file in filesList)
{ auF++;
<tr>
<td>
<span>#auF.</span>
<span #onclick="#(e=>readFile(file))" style="cursor:pointer;">#file</span>
</td> <td>
<audio controls="controls">
<source src="#file">
</audio>
</td>
</tr>
}
}
else
{
<tr>
<td>No files</td>
</tr>
}
</tbody>
</table>
Code part:
#code{
List<string> filesList = new List<string>();
string path = $"{Directory.GetCurrentDirectory()}{#"\path"}";
protected override void OnInitialized()
{
var files = Directory.GetFiles(path);
foreach (var file in files)
{
filesList.Add(Path.GetFileName(file));
}
}
public void readFile(string fileName)
{
}}
Does anyone know how I can make a file list selectable, so that I can get to choose which audio file to play by clicking on it?
The HTML Audio player can accept URL or base64 string of an audio file.
In that case, I would recommend you store the audio files in wwwroot folder as web assets eg. inside wwwroot\audio\. Then the HTML audio player can access these audio files by their url.
Additionally, I created the class AudioFile to store the audio file properties such as the last modified date and file size so that we can show that information too in the table as well.
Implementation:
#page "/"
#inject IWebHostEnvironment env
<table class="table mb-0">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Last Modified</th>
<th scope="col">Size</th>
<th scope="col">Player</th>
</tr>
</thead>
<tbody>
#if (audioList.Count > 0)
{
#foreach (var file in audioList)
{
<tr>
<td>#(audioList.IndexOf(file) + 1)</td>
<td>#file.Name</td>
<td>#file.LastModified.ToString("dd-MMM-yyyy HH:mm")</td>
<td>#FileSizeFormatter.FormatSize(file.Length)</td>
<td>
<audio controls="controls">
<source src="#file.Url">
</audio>
</td>
</tr>
}
}
else
{
<tr>
<td>No files</td>
</tr>
}
</tbody>
</table>
#code{
readonly List<AudioFile> audioList = new();
readonly string audioFolderName = "audio";
protected override void OnInitialized()
{
var path = $"{env.WebRootPath}\\{audioFolderName}\\";
var d = new DirectoryInfo(path);
var files = d.GetFiles();
foreach (var file in files)
{
audioList.Add(new AudioFile
{
Name = file.Name,
Url = $"/audio/{file.Name}",
Length = file.Length,
LastModified = file.LastWriteTime
});
}
}
public class AudioFile
{
public string Name { get; set; }
public string Url { get; set; }
public long Length { get; set; }
public DateTime LastModified { get; set; }
}
public static class FileSizeFormatter
{
static readonly string[] suffixes = { "Bytes", "KB", "MB", "GB", "TB", "PB" };
public static string FormatSize(long bytes)
{
var counter = 0;
decimal number = bytes;
while (Math.Round(number / 1024) >= 1)
{
number = number / 1024;
counter++;
}
return $"{number:n1}{suffixes[counter]}";
}
}
}
Demo:

Map Partial Json Data to Model Class

I have a API Json data that contains a lot of information, but I only need to map one attribute to my model class, say Programname, I don't care of other information. I am using Json converter to DeserializeObject the API data. Is it possible to only map partial Json data to my model class? Right now, I receive error message as below if I only map one attribute of the Json data. Thanks.
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List`1[WebApplication2.Program]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable`1[WebApplication2.Models.Program]'.
public class Program
{
public int Prog_id { get; set; }
public string Programname { get; set; }
}
Controller:
public async Task<IActionResult> Index()
{
var Client = new HttpClient();
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("appllication/json"));
HttpResponseMessage res = await Client.GetAsync("my url");
if (res.IsSuccessStatusCode)
{
var result = res.Content.ReadAsStringAsync().Result;
List<Program> programs = JsonConvert.DeserializeObject<List<Program>>(result);
return View(programs);
}
else
{
throw new Exception(res.ReasonPhrase);
}
}
View
#model IEnumerable<WebApplication2.Models.Program>
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
Program
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Programname)
</td>
</tr>
}
</tbody>
</table>
change view model to list and fix a namespace
#model List<WebApplication2.Program>
and IMHO use await instead of .Result
var result = await res.Content.ReadAsStringAsync();
List<Program> programs = JsonConvert.DeserializeObject<List<Program>>(result);
return View(programs);
I figured it out what the problem was now. The word "Program" is a reserved word in asp.net core. After I changed the Program to something else, it works. :/

Why is model data passed from view to controller null?

I have a view where I loop through the model list and display data. I am trying to pass that model to a different controller/action on link click. The data being passed is null. How do I do this?
View:
#Model TransactionViewModel
<table class="table table-striped table-hover visible-lg visible-md visible-sm " style="white-space:nowrap;">
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
<th>Tag Number</th>
<th>Payment Method</th>
<th>Prior Balance</th>
<th>Current Balance</th>
<th>Description</th>
<th>Comments</th>
<th>Receipt</th>
</tr>
</thead>
<tbody>
#if (Model != null && Model.Transactions != null)
{
#foreach (var Tran in #Model.Transactions)
{
<tr>
<td>#Tran.TimeStamp</td>
<td>#Tran.Fare</td>
<td>#Tran.FullTagNum</td>
<td>#Tran.PaymentMethod</td>
<td>#Tran.PreviousBalance</td>
<td>#Tran.NewBalance</td>
<td>#Tran.PaymentDescription</td>
<td>#Tran.Comments</td>
#if (Tran.Processing_ref_string != null)
{
<td>
Receipt
</td> /*how do I pass in the dynamic variable Tran*/
}
else
{
<td>Not Available</td>
}
</tr>
}
}
</tbody>
</table>
Controller Action:
public async Task<IActionResult> PrintReceipt(ReplenishmentRecordResponse ReceiptData){
//data manipulation
}
Model:
public class TransactionViewModel
{
[Display(Name = "From", Prompt = "Starting Date")]
public DateTime StartDate { get; set; }
[Display(Name = "To", Prompt = "Ending Date")]
public DateTime EndDate { get; set; }
public List<ReplenishmentRecordResponse> Transactions { get; set; }
}
I would utilize asp-route-id and asp-page-handler TagHelpers to route your ID back to your PrintReceipt() method.
You could have a button like:
<button id="btnDownload" class="btn btn-info" asp-route-id="#HttpContext.Request.Query["id"]" asp-page-handler="PrintReceipt" type="submit">Submit</button>
Your element needs to have name=id for this to work, but you can change id to be anything.
Simply pass in string id as your parameter in your Controller method.
public async Task<IActionResult> PrintReceipt(string id){
//do something
}
You may need to add #Tran.Tran.Processing_ref_string in your if block
Below are some good links that could also steer you in the right direction. I hope this helps!
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-3.1
TagHelper for passing route values as part of a link
https://www.learnrazorpages.com/razor-pages/tag-helpers/anchor-tag-helper

How to use a if statement in a div using thymeleaf?

If I remove the div tag from the source code below my application runs with no error. But it displays an empty cell (which is correct). I just want to hide this if the cells are empty.
Thymeleaf html
<div th:object="${AppPortModel.Status}" th:if="${AppPortModel.Status} == 'CRITICAL'">
<h3>
MONITORING
</h3>
<table id ="apCritTable">
<thead>
<tr>
<th> Status </th>
<th> HostName </th>
<th> Port Name</th>
<th> Port Listening Count </th>
</tr>
</thead>
<tbody>
<tr th:each="AppPortModel, iterStat : ${showap}" th:if="${AppPortModel.Status == 'CRITICAL'}">
<td th:text ="${AppPortModel.Status}"></td>
<td th:text="${AppPortModel.host}">${AppPortModel.host}</td>
<td th:text="${AppPortModel.portOwner}"></td>
<td th:text="${AppPortModel.count}"></td>
</tr>
</tbody>
</table>
</div>
AppPortModel
public class AppPortModel implements Comparable {
private String Status;
private String host;
private String portName;
private String plCount;
//getters and setters
#Override int compareTo(Object o) {
return //stuff
}
Controller
#Controller
public class IndexController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView getdata() throws IOException {
ModelAndView model = new ModelAndView("index");
model.addObject("showap", apList);
return model;
}
AppPortList
#Component
public class AppPortList {
#Value("#{'$APP_SERVERS_PORT}'.split('#!')}")
private String[] apServerArray;
#Value("#{'${APP_SERVER_MONITORING_LIST}'.split('#!')}")
private String[] appServerPortsList;
#PostConstruct
public List<AppPortModel> getAppPortList() {
final int MYTHREADS = 80;
ExecutorService executor = Executors.newFixedThreadPool(MYTHREADS);
ApplicationPort.resetData();
try {
for (int z = 0; z < apServerArray.length; z++) {
String apServer = apServerArray[z];
String[] portListArray=appServerPortsList[z].split(",");
ApplicationPort apWorker = new ApplicationPort(apServer, portListArray);
executor.execute(apWorker);
}
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsException in AppPortList");
}
finally {
executor.shutdown();
while (!executor.isTerminated()) {
}
logger.info("\nFinished all threads in App Port. ");
}
return ApplicationPort.getData();
}
Snippet of Class App
static List<AppPortModel> apData = new ArrayList<AppPortModel>();
public static List<AppPortModel> getData() {
return apData;
}
public static void setData(List<AppPortModel> apData) {
ApplicationPort.apData = apData;
}
public static void resetData(){
apData = new ArrayList<AppPortModel>();
}
public ApplicationPort(String apServer, String[] portListArray) {
this.apServer = apServer;
this.portListArray = portListArray;
}
This table will populate if AppPortModel.Status is CRITICAL. I am trying to hide this table if there is no values in this table. If I just have a regular div tag my code will run but I will have a awkward head and table row heads on my page with empty cells.
Attempt
I tried adding some th logic into my div tag, but I receive an null error.
<div th:object="${AppPortModel.Status}" th:if="${AppPortModel.Status == 'CRITICAL'}">
Attempt 2
<div th:if="${Status} == 'CRITICAL'">
This script would hide my div tag. Even if I have Status = to CRITICAL it would still hide the table.
You can check whether the list is empty using the following condition expression. Assuming the object showap is a List type,
<div th:if="${not #lists.isEmpty(showap)}">
--content--
</div>
Your h3 tag and table goes inside this div.
#lists is a thymeleaf utility class. Refer http://www.thymeleaf.org/apidocs/thymeleaf/2.0.2/org/thymeleaf/expression/Lists.html for more options. You can alternatively use size() method and check for list length.

Can not convert type AnonymousType?

I want to pass the results of a query (JSON) from a controller to a partial view, that's why I created a strongly type as follows:
public class Suivi_Client
{
public string ClientID { get; set; }
public string Activite { get; set; }
public string ClientName { get; set; }
}
// list
public class Suivis
{
public List<Suivi_Client> List_Clients { set; get; }
}
Then the partial view :
#model IEnumerable<Project.Models.Suivi_Client>
<html>
<body>
<table border=1>
<thead>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Activite
</th>
</tr>
</thead>
#foreach(var item in Model){
foreach (var pop in item.List_Clients)
{
<tr>
<td >
#Html.DisplayFor(modelItem => pop.ClientID)
</td>
< <td >
#Html.DisplayFor(modelItem => pop.ClientName)
</td>
<td >
#Html.DisplayFor(modelItem => pop.Activite)
</td>
</tr>
}
}
</table>
</body>
</html>
here is the action method:
public ActionResult Partial_suivi(string clients)
{
IEnumerable<Suivis> PopModel;
var activit = (from x in frh.productivites
join y in frh.Clients on x.action equals y.ClientName
where x.action.Equals(clients)
select new { x.actionID,x.Activité,y.ClientName,y.Responsable,y.TempsCible,x.tempsmoy_ }).Distinct().ToArray();
PopModel = activit;
return PartialView(PopModel);
}
but I have this error : Can not convert type 'AnonymousType # 1 []' to 'Project.Models.Suivis
how can I resolve this error ?
There's a couple issues here.
In your Action Method, you are trying to pass an IEnumerable<Suivis> to your view.
But your view is expecting an IEnumerable<Suivi_Client>.
The next problem is your linq query is selecting (transforming) into an anonymous object, but you're trying to put it into an IEnumerable<Suivis>.
I'm going to take a guess that what you want to do is make your linq query select into an IEnumerable<Suivi_Client> so that your view can do it's work. To do that you would change your code to something similar to this
IEnumerable<Suivi_Client> PopModel = (from x in frh.productivites
join y in frh.Clients on x.action equals y.ClientName
where x.Action.Equals(clients)
select new Suivi_Client
{
Activite = x.Activite,
ClientName = y.ClientName,
ClientID = ??
}).Distinct();
return PartialView(PopModel);
There are a lot of unknowns from the code you provided, and you're using objects that you didn't show in your code snippets. If you could explain what you want your linq query to do actually do, I'm sure someone could post a more complete/better example of how to achieve what you're after.