I have a piece of MVC asp.net C# that uses FineUploader. I used it in PHP before with no issues, but in asp.net c# mvc it fails (it triggers but always posts null) can anyone shed light onto why? I think it's the default transport is imprecise and it's not really using IFormFile but without any documentation from FineUploader it's impossible to know what structure they rely on for transport - regardless the c# controller fires correctly, but has null in it.
Here is the <head> markup
<!-- Fine Uploader Gallery CSS file
====================================================================== -->
<link rel="stylesheet" href="/fine-uploader/fine-uploader-new.css" />
<link rel="stylesheet" href="/fine-uploader/fine-uploader-gallery.css" />
<!-- Fine Uploader JS file
====================================================================== -->
<script src="/fine-uploader/fine-uploader.core.js"></script>
<script src="/fine-uploader/fine-uploader.js"></script>
<!-- Fine Uploader Gallery template
====================================================================== -->
<script type="text/template" id="qq-template-gallery">
<div class="qq-uploader-selector qq-uploader qq-gallery" qq-drop-area-text="Drop files here">
<div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
</div>
<div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
<span class="qq-upload-drop-area-text-selector"></span>
</div>
<div class="qq-upload-button-selector qq-upload-button">
<div>Upload a file</div>
</div>
<span class="qq-drop-processing-selector qq-drop-processing">
<span>Processing dropped files...</span>
<span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
</span>
<ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" aria-relevant="additions removals">
<li>
<span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
<div class="qq-progress-bar-container-selector qq-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<div class="qq-thumbnail-wrapper">
<img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
</div>
<button type="button" class="qq-upload-cancel-selector qq-upload-cancel">X</button>
<button type="button" class="qq-upload-retry-selector qq-upload-retry">
<span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
Retry
</button>
<div class="qq-file-info">
<div class="qq-file-name">
<span class="qq-upload-file-selector qq-upload-file"></span>
<span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
</div>
<input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
<span class="qq-upload-size-selector qq-upload-size"></span>
<button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">
<span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
</button>
<button type="button" class="qq-btn qq-upload-pause-selector qq-upload-pause">
<span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
</button>
<button type="button" class="qq-btn qq-upload-continue-selector qq-upload-continue">
<span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
</button>
</div>
</li>
</ul>
<dialog class="qq-alert-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Close</button>
</div>
</dialog>
<dialog class="qq-confirm-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">No</button>
<button type="button" class="qq-ok-button-selector">Yes</button>
</div>
</dialog>
<dialog class="qq-prompt-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<input type="text">
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Cancel</button>
<button type="button" class="qq-ok-button-selector">Ok</button>
</div>
</dialog>
</div>
</script>
Here is the <body> markup
<!-- Fine Uploader DOM Element
====================================================================== -->
<div id="fine-uploader-gallery"></div>
<!-- Your code to create an instance of Fine Uploader and bind to the DOM/template
====================================================================== -->
<script>
var galleryUploader = new qq.FineUploader({
element: document.getElementById("fine-uploader-gallery"),
template: 'qq-template-gallery',
request: {
endpoint: '#Url.Action("UploadFile", "Home")'
},
thumbnails: {
placeholders: {
waitingPath: '/fine-uploader/waiting-generic.png',
notAvailablePath: '/fine-uploader/not_available-generic.png'
}
},
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png']
}
});
</script>
Here is the HomeController.cs controller
[HttpPost]
public IActionResult UploadFile(IFormFile file)
{
if (file != null)
{
using (var reader = new StreamReader(file.OpenReadStream()))
{
string contentAsString = reader.ReadToEnd();
byte[] contentAsByteArray = GetBytes(contentAsString);
return File(contentAsByteArray, file.ContentType);
}
}
return null;
}
I know it fires the server because when I upload three items the controller fires 3 times. But all null.
incidentally, for bonus points, I am also always getting the following console errors even though the files paths are correct
By default, Fine Uploader will send the file in the body of a multipart encoded POST request. You can use Request object instead of method parameters.
The server should return valid JSON response to all requests.
[HttpPost]
public ActionResult UploadFiles()
{
string path = Server.MapPath("~/Uploads/");
var fileExists = Request.Files.Count > 0;
if (fileExists)
{
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
try
{
HttpPostedFileBase fileBase = Request.Files[0];
if (fileBase != null)
{
string fileName = Path.GetFileName(fileBase.FileName);
fileBase.SaveAs(path + fileName);
}
return Json(new { success = "true"});
}
catch (Exception ex)
{
return Json(new { success = "false", error = ex.Message });
}
}
return Json(new { success = "false"});
}
Related
I want to upload files with my data on Angular side. But when we check the data added to the form on the angular side, there is no problem, the file is null on the service side. Dto and angular variable names etc are the same. Please help me.
backendService
Backend
Dto
public class SampleAnalysisFileDto
{
IFormFile File { get; set; }
public string Name { get; set; }
}
Controller
[HttpPost("{id}")]
[GrandAuthorize(GrandPermission.EndpointPermission, Grands.SampleAnalysisUpdate + "," + Grands.SampleAnalysesByPerosonnel, GrandFilterType.Or)]
public async Task<ServiceResponse<bool>> SampleAnalysisUpdate(int id, [FromForm] SampleAnalysisFileDto model)
{
return await AspectProxy<IOrderService>.Create(_orderService).SampleAnalysisUpdate(id, model);
}
Frontend
baseService
update(apiControllerName: string, metot: string, entity: any) {
return this.http.put<any>(environment.apiUrl + '/' + apiControllerName + '/' + metot + '/' + 1, entity, { headers: this.jwt_header() });
}
SampleAnalysis ts
onFile(id: number) {
this._genelServis.onFile(id);
}
onSubmit() {
const formData: FormData = new FormData();
formData.append('file', this.file_);
formData.append('name','deneme');
this._genelServis.lodingShow();
this._baseServis.update("Order", "SampleAnalysisUpdate", formData).subscribe(
(data: any) => {
this._genelServis.lodinghide();
if (Helpers.ExcuteData(data, false) === true) {
this.onSubmitSaveAfter.emit(this.entity.id);
this.modalClose();
}
},
error => {
this._genelServis.lodinghide();
});
}
Frontend html
<div class="modal-header">
<h4 class="modal-title"><app-language-com [labelCode]="'UI_ANALIZI_RAPOR'"></app-language-com></h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.close('Close click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div fxLayout="row" fxLayoutWrap="wrap">
<!-- column -->
<div fxFlex.gt-sm="100" fxFlex.gt-xs="100" fxFlex="100">
<mat-card>
<mat-card-content>
<!-- Row -->
<form class="basic-form" (ngSubmit)="onSubmit()" autocomplete="off" enctype="multipart/form-data">
<div fxLayout="row wrap" class="vys-form-element">
<!-- column -->
<div fxFlex.gt-md="100" fxFlex="100" class="vys-form-element" style="margin-top: 10px;">
<mat-form-field>
<mat-label>* <app-language-com [labelCode]="'UI_RAPOR_ACIKLAMA'"></app-language-com></mat-label>
<textarea matInput type="text" value="" name="input1reportContent" [(ngModel)]="entity.reportContent" style="height: 105px;" maxlength="2000"></textarea>
</mat-form-field>
<app-knumber-com [entity]="entity?.statusContent" [knumber]="2000"></app-knumber-com>
</div>
<div fxFlex.gt-sm="100" fxFlex="100" class="vys-form-element">
<input type="file" id="files" style="display: contents;" (change)="onfileSelected($event)" />
<a href="javascript:;" title="Rapor Seç">
<mat-icon _ngcontent-feo-c354="" role="img" for="files" class="mat-icon notranslate material-icons mat-icon-no-color" aria-hidden="true" data-mat-icon-type="font">file_download</mat-icon>
<label for="files">Rapor Seç</label>
</a>
<label>{{fileName}}</label>
<a href="javascript:;" title="Dosyayı Sil" (click)="entity.reportFileId = 0;fileName = '';" *ngIf="entity.reportFileId > 0">
<mat-icon _ngcontent-feo-c354="" role="img" for="files" class="mat-icon notranslate material-icons mat-icon-no-color" aria-hidden="true" data-mat-icon-type="font">delete</mat-icon>
<label>Dosyayı Sil</label>
</a>
</div>
<div fxFlex.gt-sm="70" fxFlex="70" style="text-align: right;margin-top:10px">
<button mat-raised-button color="primary" type="submit"><app-language-com [labelCode]="'UI_KAYDET'"></app-language-com></button>
<button type="button" class="btn btn-light" id="modalUsercloseId" (click)="activeModal.close('Close click')"><app-language-com [labelCode]="'UI_KAPAT'"></app-language-com></button>
</div>
</div>
</form>
</mat-card-content>
</mat-card>
</div>
<!-- column -->
</div>
I'm writing an application using Blazor server side and .Net 5. I want when I write text in the search box it will show results in new divs. However, the search results are not displayed. When I debug the code from service works fine.
#page "/"
#using MovieSearch.Service
#using MovieSearch.Data
#using MovieSearch.Helpness
#inject IOMDbService service
<div class="movie-search">
<div class="search-container">
<form action="/">
<input type="text" placeholder="Find a movie" #bind-value="#searchTerm" />
<button type="submit" #onclick="FindMovies"><i class="fa fa-search"></i></button>
</form>
</div>
</div>
<div class="movies">
#if(moviesResult != null)
{
if(!moviesResult.Success)
{
foreach(var error in moviesResult.Errors)
{
<p>#error.Message</p>
}
}
else
{
foreach(var movie in moviesResult.Value)
{
<div class="movie">
<p>#movie.Title</p>
<img src="#movie.Poster" />
</div>
}
}
}
</div>
#code
{
private string searchTerm;
private Result<IEnumerable<Movie>> moviesResult;
async Task FindMovies()
{
moviesResult = await service.FindMovies(searchTerm);
}
}
What can I do to view the results?
Try changing this part of your code from
<form action="/">
<input type="text" placeholder="Find a movie" #bind-value="#searchTerm" />
<button type="submit" #onclick="FindMovies"><i class="fa fa-search"></i></button>
</form>
to just this
<input type="text" placeholder="Find a movie" #bind-value="#searchTerm" />
<button #onclick="FindMovies"><i class="fa fa-search"></i></button>
So in other words, remove the form tags, as well as removing the type on the button. I believe that blazor is now actually trying to post the form to whatever action you specified in the form as opposed to the onclick handler you assigned to your button.
I have a simple application in .NET Core MVC, with this simple form. When I try to post the form without refresh whole page only rest the form and got the result of done.
My code trial is:
<form asp-area="" asp-controller="ContactUs" asp-action="UserMessage" data-ajax="true">
<h5>Reach us quickly</h5>
<div class="row">
<span asp-validation-for="UserName" class="text-danger"></span>
<div class="col-sm-6 col-12">
<div class="form-group">
<input asp-for="UserName" class="form-control" name="UserName" placeholder="Enter name" required="required">
</div>
</div>
<span asp-validation-for="Email" class="text-danger"></span>
<div class="col-sm-6 col-12">
<div class="form-group">
<input asp-for="Email" class="form-control" name="Email" placeholder="Enter email" required="required">
</div>
</div>
</div>
<div class="row">
<span asp-validation-for="Msg" class="text-danger"></span>
<div class="col-12">
<div class="form-group">
<textarea asp-for="Msg" name="Msg" class="form-control" rows="7" cols="25" placeholder="Message"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 mt-3">
<button type="submit" class="btn solid-btn" id="btnContactUs">
Send Message
</button>
</div>
</div>
</form>
and my action is:
[HttpPost]
public async Task<IActionResult> UserMessage(ContactUs model)
{
try
{
if (ModelState.IsValid)
{
_context.Add(model);
await _context.SaveChangesAsync();
return NoContent();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return NoContent();
}
I want to change return NoContent(); so I can show a message to the user that his message has sent or failed, without refreshing the whole page.
Your form tag is missing some other ajax attributes:
<form method="post"
data-ajax="true"
data-ajax-method="post"
data-ajax-url="#Url.Page("UserMessage", "ContactUs")"
data-ajax-loading="#loading"
data-ajax-mode="replace"
data-ajax-update="#updateDiv">
<!-- form controls -->
<button type="submit" class="btn solid-btn" id="btnContactUs">Send Message</button>
<span id="loading" style="display:none;"> <i class="fas fa-spinner fa-spin"></i></span>
</form>
<div id="updateDiv">
<!-- ajax content will load here -->
<!-- you can put the form inside this div -->
<!-- so after submit the result will replace the form controls -->
</div>
<!-- include jquery libraries -->
#section Scripts {
<script src="https://cdn.jsdelivr.net/npm/jquery#3.5.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ajax-unobtrusive#3.2.6/dist/jquery.unobtrusive-ajax.min.js"></script>
}
The backend method can return the result as below:
public async Task<ContentResult> OnPostUserMessageAsync(ContactUs model)
{
try
{
if (ModelState.IsValid)
{
_context.Add(model);
await _context.SaveChangesAsync();
return Content("done");
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return Content("something went wrong...");
}
See Ajax Request Using Inline Attributes
If you don't want the page to be replaced, you'll have to use ajax to post the data via javascript. Posting a form in a browser will replace the current html with the result of the controller, that's just how forms work.
It is also common practice to redirect any successful POST to a different page, so that the user can refresh that page without processing the POST request twice.
thanks for #Laz Ziya i have used his code and modify form to be
instead of
<form method="post"
data-ajax="true"
data-ajax-method="post"
data-ajax-url="#Url.Page("UserMessage", "ContactUs")"
data-ajax-loading="#loading"
data-ajax-mode="replace"
data-ajax-update="#updateDiv">
to be
<form asp-area="" asp-controller="ContactUs" asp-action="UserMessage" data-ajax-loading="#loading" data-ajax-mode="replace" data-ajax-update="#updateDiv" data-ajax-success="Success" data-ajax-failure="Failure" data-ajax="true">
for post form without refresh ,you need to use ajax in your code.
I'm trying to refresh my Partial View after submitting a form which will be processed in my controller. The problem is that whenever I try to refresh it form my controller, I get redirected to a blank page with content from the Partial View.
Partial View
#model Smarty.Viewmodels.BugViewModel
<div class="modal fade" id="bugModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Bug Reporting Tool</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span>×</span>
</button>
</div>
<form asp-controller="Smarty" asp-action="SendBugReport" enctype="multipart/form-data">
#if (!string.IsNullOrWhiteSpace(ViewBag.message))
{
if (!ViewBag.IsError)
{
<span class="border border-success text-success">#ViewBag.message</span>
}
else
{
<span class="border border-danger text-danger">#ViewBag.message</span>
}
}
<div class="modal-body">
<label asp-for="Description" class="control-label"></label>
<textarea asp-for="Description" class="form-control"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
<label asp-for="FormFile" class="control-label"></label><br />
<input asp-for="FormFile" type="file" />
<span asp-validation-for="FormFile" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schliessen</button>
<button type="submit" id="BugReportBtn" class="btn btn-success">Bug Report senden</button>
</div>
</form>
</div>
</div>
</div>
Controller
public async Task<IActionResult> SendBugReport(BugViewModel viewModel)
{
//Process Form
return PartialView("BugModal", viewModel);
}
Thanks in advance!
I get redirected to a blank page with content from the Partial View.
That is expected because you use return PartialView() which will return the simple partial html to render it into the view.
I want to refresh the Partial View with content like Error Messages, Success messages etc
You could not get #ViewBag.message from the SendBugReport action, it is passed from the action of main page.
As the comment has said that, first of all, you could use ajax to submit the form to SendBugReport action.Then the action return message and isError json data to ajax success function. Finally, you render message on the view based on the value of isError:
1.Partial View (Views/Shared/BugModal.cshtml)
#model BugViewModel
<div class="modal fade" id="bugModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Bug Reporting Tool</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span>×</span>
</button>
</div>
<form id="myForm" asp-controller="Smarty" asp-action="SendBugReport" enctype="multipart/form-data">
<div id="result"></div>
<div class="modal-body">
<label asp-for="Description" class="control-label"></label>
<textarea asp-for="Description" class="form-control"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
<label asp-for="FormFile" class="control-label"></label><br />
<input asp-for="FormFile" id="FormFile" name="FormFile" type="file" />
<span asp-validation-for="FormFile" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schliessen</button>
<button type="button" id="BugReportBtn" class="btn btn-success">Bug Report senden</button>
</div>
</form>
</div>
</div>
</div>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script>
$('#BugReportBtn').on('click', function (event) {
var url = "/Smarty/SendBugReport";
var description = document.getElementById("Description").value;
var fileInput = $('#FormFile')[0];
var formFile = fileInput.files[0];
var formData = new FormData();
formData.append("Description", description);
formData.append("FormFile", formFile);
$.ajax({
type: "POST",
url: url,
data: formData,
dataType: "json",
processData:false,
contentType: false,
success: function (data) {
if (!data.isError) {
$("#result").html("<span class='border border-success text-success'>" + data.message + "</span>");
} else {
$("#result").html("<span class='border border-danger text-danger'>" + data.message + "</span>");
}
$('#bugModal').modal('show');
}
});
});
</script>
2.Action
[HttpPost]
public async Task<JsonResult> SendBugReport(BugViewModel viewModel)
{
//Process Form
string message;
bool isError;
//set data to message and isError
return Json(new { message, isError });
}
net mvc 5 application and for this I use bootstrap because it looks fine.
I don't want to use for an input and a searchbutton the
#using (Html.BeginForm("...
Can I control the html tags without this from my controller. For example here is my index.cshtml
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container">
<div class="row">
<h2>Suche</h2>
<div id="custom-search-input">
<div class="input-group col-md-12">
<input type="text" class=" search-query form-control" placeholder="Search" />
<span class="input-group-btn">
<button class="btn btn-danger" type="button">
<span class=" glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</div>
</div>
</div>
I want if I click on the Searchbutton I get a message with the text from the inputfield.
Here is the Controller:
public ActionResult Search(string value)
{
//listofUsers is a arraylist of all users that found^^
return View(listofUsers);
}
How I can do this? :)
Add a div to show the result:
<div id="custom-search-input">
<div class="input-group col-md-12">
<input type="text" class=" search-query form-control" placeholder="Search" />
<span class="input-group-btn">
<button class="btn btn-danger" type="button">
<span class=" glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</div>
<div class="custom-search-result"></div>
Then in a script tag or a linked js file:
$(document).ready(function () {
$('.custom-search-input').each(function () {
var sinput = $(this);
var svalue = sinput.find('input');
var sresult = sinput.next('.custom-search-result');
sinput.find('button').click(function () {
$.ajax({
url: '/ControllerName/Search?value=' + svalue.val(),
type: 'GET'
}).done(function (result) {
sresult.html(result);
});
});
});
});
This is a basic example with no error handling.
First I highly recommend reading Philip Walton (Google) - Decoupling your HTML, CSS and Javascript, it's extremely good.
Here how I would use MVC to it's full potential.
Model:
// Extensible Programming
// Using a string limits additional features
// Future proofing via a class that takes 2 minutes to create
public class GlobalSearch
{
public string SearchTerms { get; set; }
}
View:
#Model GlobalSearch
<div class="container">
<div class="row">
<h2>Suche</h2>
<div id="custom-search-input">
#using (Html.BeginForm("Search"))
{
<div class="input-group col-md-12">
#Html.TextBoxFor(m => m.SearchTerms, new {
#class="search-query form-control",
placeholder="Search" })
<span class="input-group-btn">
<button class="btn btn-danger" type="button">
<span class=" glyphicon glyphicon-search js-form-submit"></span>
</button>
</span>
</div>
}
</div>
</div>
</div>
Controller:
// Strongly Typed Class is Returned
public ActionResult Search(GlobalSearch search)
{
return View(listofUsers);
}
The following script will require this fantastic script called form2js which correctly converts any strongly-typed forms generated by MVC (arrays, lists etc) into Json that will be ModelBinded correctly.
$(document).ready(function() {
('.js-form-submit').on('click', function() {
var $form = $(this).closest('form');
var json = form2js($form);
var ajaxSettings = {
url: $form.attr('action'),
type: $form.attr('method'),
data: json,
contentType: "application/json",
}
$.ajax(ajaxSettings)
.done()
.always()
.fail();
});
});
Of course this could be easily abstract into it's own javascript class/namespace that returns the promise and reusable on any form that simply has a button with the class js-form-submit instead of continually rewriting $.ajax over and over again each time for different forms.