How can I delete a specific uploaded file in mvc5? - asp.net-mvc-5

After I upload a file, I would want to be able to delete it. I tried doing so, but I get the error "The resource cannot be found". Also, how can I make edit buttons for every file from the row, in order to upload a better version of that specific file? Could someone help me?
This is my controller:
public class FileUploadController : Controller
{
// GET: FileUpload
public ActionResult Index()
{
var items = GetFiles();
return View(items);
}
// POST: FileUpload
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
if(file != null && file.ContentLength > 0 )
try
{
string path = Path.Combine(Server.MapPath("~/Files"),
Path.GetFileName(file.FileName));
file.SaveAs(path);
ViewBag.Message = "File uploaded successfully";
}
catch(Exception ex)
{
ViewBag.Message = "ERROR:" + ex.Message.ToString();
}
else
{
ViewBag.Message = "You have not specified a file.";
}
var items = GetFiles();
return View(items);
}
public FileResult Download(string downloadedfile)
{
var FileVirtualPath = "~/Files/" + downloadedfile;
return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
private List <string> GetFiles()
{
var dir = new System.IO.DirectoryInfo(Server.MapPath("~/Files"));
System.IO.FileInfo[] fileNames = dir.GetFiles("*.*");
List<string> items = new List<string>();
foreach (var file in fileNames)
{
items.Add(file.Name);
}
return items;
}
[HttpPost]
public ActionResult Delete(string file)
{
file = Path.Combine(Server.MapPath("~/Files"), file);
FileInfo fl = new FileInfo(file);
if (fl != null)
{
System.IO.File.Delete(file);
fl.Delete();
}
return View();
}
}
}
This is the view, the only problem with it is the Delete section:
<h2> File Upload </h2>
#model List<string>
#using (Html.BeginForm("Index", "FileUpload", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<label for="file"> Upload </label>
<input type="file" name="file" id="file" />
<br /><br />
<input type="submit" value="Upload" />
<br /><br />
#ViewBag.Message
<br />
<h2>Documents list</h2>
<table style="width:100%">
<tr>
<th> File Name </th>
<th> Link </th>
</tr>
#for (var i = 0; i <= (Model.Count) - 1; i++)
{
<tr>
<td>#Model[i].ToString() </td>
<td>#Html.ActionLink("Download", "Download", new { downloadedfile = Model[i].ToString() }) </td>
<td>#Html.ActionLink("Delete", "Delete", new { deletedfile = Model[i].ToString() }) </td>
</tr>
}
</table>
}

In the form you're posting to the delete method, there is nothing indicating what the path to the file to delete is. You do have a hidden input for the Count property, but if that was a hidden input named "file" and contained the path value for the file to be deleted, then it would be posted.
Note, for security reasons you likely do NOT want to allow people to just post the path to any file and the server will delete it. That could get you into a lot of trouble. You likely should be storing a database record with the file url and an ID and posting that ID to the server, and reading the URL from the database, then deleting the file.

Related

How to use seach function by "int" in ASP.NET Core MVC?

I use this way add seach function.
But it only can search by string.
I want to add a function of seach by "int".
Anyone have suggest?
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(await movies.ToListAsync());
}
And it is my resource
https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/search?view=aspnetcore-5.0
Also I have try like this way,but it seem didn't work
Search By Number in ASP.NET MVC
To search value by Int parameter, it is similar like search by string. In the View page, set the element's name attribute as same as the parameter name in the action method.
You can check the following sample:
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="searchString" value="#ViewData["CurrentFilter"]" />
Find by ID: <input type="text" name="searchId" value="#ViewData["CurrentID"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
Controller:
public async Task<IActionResult> Index(string searchString, int searchId)
{
var students = from stu in _context.Students
select stu;
//if (!String.IsNullOrEmpty(searchString))
//{
// students = students.Where(s => s.LastName.Contains(searchString.ToString()));
//}
if (searchId !=0)
{
students = students.Where(s => s.ID == searchId );
}
ViewData["CurrentFilter"] = searchString;
ViewData["CurrentID"] = searchId;
return View(await students.ToListAsync());
}
Then, the result as below:

Posting an array of string

I am trying to post a string array to the post action in an Razor Pages project. For this, I thought about using a hidden <select> tag. The user would enter text into a text box, press a button and I would then add a new option to the <select> then post the whole thing with a submit button. However, after everything is posted, the array property of my model is empty.
Does anyone know if there is a better way of doing this or what I am doing wrong?
Razor:
<form method="post">
<input id="string-value" />
<input type="button" id="add-item" value="Add item" />
<select asp-items="#Model.Model.ArrayOfStrings" id="hidden-select"></select>
<table id="table-items">
</table>
<input type="submit" value="Submit" />
</form>
public class ArrayModel
{
public List<SelectListItem> ArrayOfStrings { get; set; } = new List<SelectListItem>();
}
public class IndexModel : PageModel
{
[BindProperty]
public ArrayModel Model { get; set; }
public void OnGet()
{
Model = new ArrayModel();
}
public void OnPost()
{
System.Diagnostics.Debugger.Break();
}
}
JS:
$('#add-item').on('click', function () {
debugger;
var value = $('#string-value').val();
$('#hidden-select').append(new Option(value, value));
$('#table-item tr:last').after('<tr><td>' + value + '</td></tr>')
});
Repository can be found here.
The options of the select will not be posted so this will not work.
The easiest way to do this is append the results to a hidden input with a separator char, then do a string split on the server side.
Another, maybee more elegant way, would be to add hidden inputs with the same name. Each input with it's own value. You should then be able to get this as a List or Array on the server.
Razor:
<input value="#String.Join(",", Model.Model.ArrayOfStrings)" id="tags"></select>
JS
$('#tags').val($('#tags').val() + ',' + value);
Controller
public void OnPost(string tags)
{
var tagsArray = tags.split(',');
}

a4j:support partial update before submit the form

I want to make quick search in the JSF page before I submit the form (partial update) , so I have two values, one is input text and I want the result show in the output text when the user enter the value in the input text. for example I want to search about the name of the user using the user id, so in the input text the user will enter the user id (e.g 2323) then the search will happens and this will render the output text with the name of this user(2323).
I use a4j:support in order to achieve this but nothing shown with me and there is no any error or exception.
this is my JsF page:
<tr>
<td>
<table>
<tr>
<td width="80px"><h:outputLabel
value="user id"></h:outputLabel></td>
<td width="5px"> </td>
<td><h:inputText id="secondIdNum" maxlength="6" style="width:240px"
value="#{ideaDetailsBean.addIdeaDto.secondId}">
<a4j:support event="onchanged" actionListener="#
{ideaDetailsBean.secondIdChange}"
reRender="secondNameId" />
</h:inputText></td>
<td width="15px"> </td>
<td width="80px"><h:outputLabel value="user name "></h:outputLabel></td>
<td width="5px"> </td>
<td><h:outputText id="secondNameId"
style="width:240px"
value="#{ideaDetailsBean.addIdeaDto.secondName}"></h:outputText>
</td>
</tr>
</table>
</td>
</tr>
in the backbean:
public void secondIdChange(ActionEvent actionEvent) {
if(addIdeaDto.getSecondId() != null){
addIdeaDto.setSecondName(getParticipantName(addIdeaDto.getSecondId()));
}
}
static String getParticipantName(String employeeId) {
IIMDelegate iimDelegate = new IIMDelegate();
UserInfoDto userInfoDto = new UserInfoDto();
iimDelegate.getParticipant(employeeId);
return userInfoDto.getUserName();
}
in the DAO:
public UserInfoDto getParticipant(String employeeId) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet searchResultSet = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(
"SELECT U_NAME FROM APPL_USER WHERE U_LOGIN = ?");
// Assign first value to first parameter
preparedStatement.setString(1, employeeId);
searchResultSet = preparedStatement.executeQuery();
return getParticipant(searchResultSet);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
searchResultSet.close();
preparedStatement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
private UserInfoDto getParticipant(ResultSet searchResultSet) throws SQLException {
List<UserInfoDto> result = new ArrayList<UserInfoDto>();
UserInfoDto userInfoDto = null;
while (searchResultSet.next()) {
userInfoDto = new UserInfoDto();
userInfoDto.setUserName(searchResultSet.getString(1));
result.add(userInfoDto);
}
return result == null ? null : result.size() > 0 ? result.get(0) :null;
}
Any suggestion to achieve this in different way?

RazorEngine - How to use a complex model view?

Anyone have experience working with a complex model and RazorEngine?
Working on generating HTML using RazorEngine version 3.7.3, but running into issues with the complex model view we have. It seems like we should be able to use the templates to get RazorEngine to discover the SubSample below, but have not discovered the proper way to tell RazorEngine about the associated cshtml file.
In the example below we are looking to use a shared template for the SubSample class using the SubSample.cshtml file. As can be seen from the results, the class namespace (ReportSample.SubSample) is displayed rather than an HTML row of data.
We have tried implementing an ITemplateManager, but Resolve() is never called with a key asking for the SubSample. Also tried AddTemplate() on the service, but still no joy.
Here is a simplified example model to illustrate the issue:
namespace ReportSample
{
public class SubSample
{
public string Name { get; set; }
public string Value { get; set; }
}
public class SampleModel
{
public SubSample SubSample { get; set; }
}
}
SampleModel.cshtml
#using ReportSample
#*#model ReportSample.SampleModel*#
<table style="width: 7.5in" align="center">
<tr>
<td align="center">
<h1>
Sample Report
</h1>
</td>
</tr>
<tr>
<td>
<table style="width: 100%">
<tr>
<td colspan="2">
<b>Name:</b> #Model.SubSample.Name
</td>
<td colspan="2">
<b>Value:</b> #Model.SubSample.Value
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="center">
<h1>
Sub-sample Data
</h1>
</td>
<td>
<table style="width: 100%">
#Model.SubSample
</table>
</td>
</tr>
</table>
SubSample.cshtml
#model ReportSample.SubSample
#using FSWebportal.Infrastructure.Mvc;
<tr class="observation-row">
<td class="observation-label">
#model.Name
</td>
<td class="observation-view">
#model.Value
</td>
</tr>
Basic RazorEngine calls:
private void html_Click(object sender, EventArgs e)
{
var gen = new RazorEngineGenerator();
var cshtmlTemplate = File.ReadAllText("Sample.cshtml");
var sample = new SampleModel() { SubSample = new SubSample() { Name = "name", Value = "value" } };
var html = gen.GenerateHtml(sample, cshtmlTemplate);
}
public string GenerateHtml<T>(T model, string cshtmlTemplate)
{
var config = new TemplateServiceConfiguration();
using (var service = RazorEngineService.Create(config))
{
return service.RunCompile(cshtmlTemplate, "", typeof(T), model);
}
}
Sample HTML Output:
Sample Report
Name: name
Value: value
Sub-sample Data
ReportSample.SubSample
I'm sorry but I don't think I fully understand your question but I have a small idea of what you are trying to do...
I think what you want are searching for are partial templates (using #Include)!
using RazorEngine;
using RazorEngine.Templating;
using System;
namespace TestRunnerHelper
{
public class SubModel
{
public string SubModelProperty { get; set; }
}
public class MyModel
{
public string ModelProperty { get; set; }
public SubModel SubModel { get; set; }
}
class Program
{
static void Main(string[] args)
{
var service = Engine.Razor;
// In this example I'm using the default configuration, but you should choose a different template manager: http://antaris.github.io/RazorEngine/TemplateManager.html
service.AddTemplate("part", #"my template");
// If you leave the second and third parameters out the current model will be used.
// If you leave the third we assume the template can be used for multiple types and use "dynamic".
// If the second parameter is null (which is default) the third parameter is ignored.
// To workaround in the case you want to specify type "dynamic" without specifying a model use Include("p", new object(), null)
service.AddTemplate("template", #"<h1>#Include(""part"", #Model.SubModel, typeof(TestRunnerHelper.SubModel))</h1>");
service.Compile("template", typeof(MyModel));
service.Compile("part", typeof(SubModel));
var result = service.Run("template", typeof(MyModel), new MyModel { ModelProperty = "model", SubModel = new SubModel { SubModelProperty = "submodel"} });
Console.WriteLine("Result is: {0}", result);
}
}
}
I have added documentation for this here: https://antaris.github.io/RazorEngine/LayoutAndPartial.html
However I think making #Model.SubSample work is possible as well, you can either change the SubSample property to be of type TemplateWriter or make the SubSample class implement IEncodedString. But I think you should consider partial templates first!

Viewmodel IEnumerable property is empty

I'm in the middle of making an ASP .NET MVC4 based app. I'm a complete newb in that field. The idea is quite simple - have a some members in DB, show them listed, select desired ones via check boxes and redirect to some other controller which would do something with the previously selected members.
Problem is passing the list of members from View to the Controller. I've thought it would work with ViewModel. It certainly works from Controller to the View, but not the other way.
My ViewModel:
public class MembersViewModel
{
public IEnumerable<Directory_MVC.Models.Member> MembersEnum { get; set; }
public string Test { get; set; }
}
Snippet of my Controller:
public class MembersController : Controller
{
private MainDBContext db = new MainDBContext();
public ActionResult Index()
{
var model = new Directory_MVC.ViewModels.MembersViewModel();
// populating from DB
model.MembersEnum = db.Members.Include(m => m.Group).Include(m => m.Mother).Include(m => m.Father);
model.Test = "abc";
return View(model);
}
[HttpPost]
public ActionResult GoToSendEmail(Directory_MVC.ViewModels.MembersViewModel returnedStruct)
{
if (ModelState.IsValid)
{
// it is valid here
return Redirect("http:\\google.com");
}
}
Snippet of my View:
#model Directory_MVC.ViewModels.MembersViewModel
#{
ViewBag.Title = "Members listing";
var lineCount = 0;
string lineStyle;
}
#using (Html.BeginForm("GoToSendEmail", "Members", FormMethod.Post))
{
<table>
#foreach (var item in Model.MembersEnum)
{
lineCount++;
// set styling
if (lineCount % 2 == 1)
{
lineStyle = "odd-line";
}
else
{
lineStyle = "even-line";
}
<tr class="#lineStyle">
<td>
#Html.EditorFor(modelItem => item.Selected)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mother.FirstName) #Html.DisplayFor(modelItem => item.Mother.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Father.FirstName) #Html.DisplayFor(modelItem => item.Father.LastName)
</td>
<!-- other print-outs but not all properties of Member or Mother/father are printed -->
</tr>
}
</table>
<input type="submit" value="Send E-mail" />
}
The data are shown OK in the View. However, when I submit that form the returnedStruct.MembersEnum and Test string are both null in the Controller's method GoToSendEmail.
Is there a mistake or is there another possible way how to pass that members structure and check their Selected property?
Model binding to a collection works a little differently. Each item has to have an identifier so that inputs don't all have the same name. I've answered a similar question here.
#for (int i = 0; i < Model.MembersEnum.Count(); i++)
{
#Html.EditorFor(modelItem => modelItem.MembersEnum[i].FirstName)
}
...which should render something like...
<input type="text" name="MembersEnum[0].FirstName" value="" />
<input type="text" name="MembersEnum[1].FirstName" value="" />
<input type="text" name="MembersEnum[2].FirstName" value="" />
...which should then populate the collection in your ViewModel when picked up by the controller...
public ActionResult GoToSendEmail(ViewModels.MembersViewModel model)
As mentioned in the other answer, I'd have a look at some related articles from Scott Hansleman and Phil Haack.
You also mentioned that your string called Test is null when you submit to your POST action. You haven't added a field for this property anywhere within your form, so there's nothing for the model binder to bind to. If you add a field for it within your form then you should see the value in the POST action:
#Html.EditorFor(modelItem => modelItem.Test)
Html.BeginCollectionItem() helper did the job - BeginCollectionItem.

Resources