I try create a project using Blazor(server-side) and create the views as .razor, and I also add the Controller. How can I pass data from controller to views .razor ?
I think I can create a public variable in the controller, that will be interaction Controller and .razor. But I don't know for the Code
I want get var u to the view
//Controller
[HttpPost("[action]")]
public void Save(IList<IFormFile> UploadFiles)
{
var u = UploadFiles.FirstOrDefault().FileName;
long size = 0;
size = SaveUploadedFiles(UploadFiles, size);
}
//View
<EjsUploader ID="UploadFiles">
<UploaderAsyncSettings SaveUrl="api/Save" RemoveUrl="api/Remove"></UploaderAsyncSettings>
</EjsUploader>
Syncfusion support here.
You can pass the data from the controller either using “Headers” or “ReasonPhrase” to the view in the success event as mentioned in the below code example.
[SampleDataController.cs]
public void Save(IList<IFormFile> UploadFiles)
{
long size = 0;
try
{
foreach (var file in UploadFiles)
{
var filename = ContentDispositionHeaderValue
.Parse(file.ContentDisposition)
.FileName
.Trim('"');
filename = hostingEnv.ContentRootPath.Replace("WebApplication6.Server", "WebApplication6.Client") + $#"\{filename}";
size += (int)file.Length;
if (!System.IO.File.Exists(filename))
{
using (FileStream fs = System.IO.File.Create(filename))
{
file.CopyTo(fs);
fs.Flush();
}
}
}
Response.Headers.Add("custom-header", "Syncfusion");
Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Syncfusion Upload";
}
catch (Exception e)
{
Response.Clear();
Response.StatusCode = 204;
Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "File failed to upload";
Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = e.Message;
}
}
[index.razor]
#using Newtonsoft.Json;
#using Newtonsoft.Json.Converters;
<EjsUploader Id="UploadFiles" AutoUpload="true" Success="#OnSuccess">
<UploaderAsyncSettings SaveUrl="api/SampleData/Save" RemoveUrl="api/SampleData/Remove"></UploaderAsyncSettings>
</EjsUploader>
<p>Additional Header Text is: #HeaderData</p>
<p>Additional Response Data is: #ResponseData</p>
#code{
public string HeaderData;
public string ResponseData;
public void OnSuccess(object args)
{
SuccessEventArgs eventArgs = JsonConvert.DeserializeObject<SuccessEventArgs>(args.ToString());
HeaderData = eventArgs.Response.Headers;
ResponseData = eventArgs.Response.StatusText;
this.StateHasChanged();
}
//Success event args class.
public class SuccessEventArgs
{
public object E { get; set; }
public FileInfo File { get; set; }
public string StatusText { get; set; }
public string Name { get; set; }
public string Operation { get; set; }
public ResponseEventArgs Response { get; set; }
}
public class ResponseEventArgs
{
public string Headers { get; set; }
public object ReadyState { get; set; }
public object StatusCode { get; set; }
public string StatusText { get; set; }
public bool withCredentials { get; set; }
}
}
And, you need to enable the allow header option in the Startup.cs file as mentioned in the below code example.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddNewtonsoftJson();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.AddCors(options =>
{
options.AddPolicy("EnableCORS", builder =>
{
builder.AllowAnyOrigin().AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials().Build();
});
});
}
We have prepared the sample and attached below.
Sample Link:
https://www.syncfusion.com/downloads/support/directtrac/242743/ze/WebApplication6_additional_data-460323506
Also, currently we are working on to provide the specific type for success event arguments and this support will be included in our patch release scheduled on mid of August 2019. We appreciate your patience until then.
You can track the status of the issue from the below feedback link.
Link: https://www.syncfusion.com/feedback/7647/need-to-provide-specific-type-for-success-event-arguments-in-the-uploader
Related
Controller:
[HttpPost("CreateEmail")]
[Consumes("multipart/form-data")]
public async Task<ApiResponse<Guid>> PostEmailToProcess([FromForm]EmailToProcess email)
{
try
{
var emailToAdd = new EmailToProcessDto(email);
emailToAdd.Created = DateTime.Now;
var emailId = await _emailRepository.PostEmailAsync(emailToAdd);
foreach (var file in email)
{
if (email.IFormFile != null)
{
await _contentUploadService.Upload(file, emailId.Data);
}
}
etc
EmailToProcess Object:
{
public class EmailToProcess
{
public string From { get; set; }
public string To { get; set; }
...
public List<IFormFile> IFormFile { get; set; }
}
}
As you can see in the image, swagger is only letting me submit 1 FormFile. I am new to swagger and creating APIs so Im sure Im missing something small.
I'm having a hard time to bind one particular field called url in a List.
This is my json format:
{
id: 'someID',
name: 'someName.pdf',
url: {
download: 'https://mydomain/api_binary/v1/document/mcipv7sgq11c9e6e42upqapc7k '
}
}
This is my model
public class CantoItem
{
public string id { get; set; }
public string name { get; set; }
[JsonProperty("default")]
public DefaultNest Default { get; set; }
[JsonProperty("url")]
public ResultUrl Url { get; set; }
[JsonProperty("tag")]
public object Tag { get; set; }
}
public partial class ResultUrl
{
[JsonProperty("preview")]
public Uri Preview { get; set; }
[JsonProperty("download")]
public Uri Download { get; set; }
}
[JsonProperty("tag")]
public List<string> Tag { get; set; }
}
Then for adding the value I have:
var cantoAssetMetadata = new List<CantoItem>();
foreach (JValue item in collection)
{
try
{
var collectionjObj = JObject.Parse(item.ToString());
cantoAssetMetadata.Add(new CantoItem()
{
id = collectionjObj["id"].ToString(),
name = collectionjObj["name"].ToString(),
Url = collectionjObj["url"].ToString(),
Tag = collectionjObj["tag"].ToString(),
});
}
catch (Exception ex)
{
Console.WriteLine($"Exeption: {ex}, {item}");
}
}
Other fields are set correctly just the URL is not, I can´t figure out how I can set the value correctly. Any help will be appreciated
The following wouldn't work:
Url = collectionjObj["url"].ToString()
You will need to initialize the Url and set the related property:
name = collectionjObj["name"].ToString(),
Url = new ResultUrl()
{
Download = new System.Uri(collectionjObj["url"].ToString())
},
Tag = collectionjObj["tag"].ToString(),
Why not try
var cantoAssetMetadata = new List<CantoItem>();
foreach (JValue item in collection)
{
try
{
cantoAssetMetadata.Add(item.ToObject<CantoItem>());
}
catch (Exception ex)
{
Console.WriteLine($"Exeption: {ex}, {item}");
}
}
You are calling .ToString() on a class object - Url = collectionjObj["url"].ToString(), Url is a partial class called ResultUrl. Convert the JToken to the appropriate class which it deserializes to
//Convert to the proper class object type
Url = collectionjObj["url"].ToObject<ResultUrl>;
I would like to have a function that when an exception is given to it, it will extract all the information about that exception and then write it to a database.
Before going to .NET Core 2, I was able to do this in the following manner:
var details = new ErrorDetails();
if (ex == null) return details;
var st = new StackTrace(ex, true);
var frames = st.GetFrames();
if (frames != null && frames.Length > 0)
{
var errorDetails = frames.Select(frame => new ErrorDetails
{
FileName = frame.GetFileName(),
LineNumber = frame.GetFileLineNumber().ToString(),
MethodName = frame.GetMethod().Name,
ClassName = frame.GetMethod().DeclaringType.FullName
});
return errorDetails.FirstOrDefault();
}
return details;
Ever since switching my project to .NET Core 2, this code comes back with most of this information being null/default; I took a look at the frames that I extract, and they don't have the information anymore. For things like FileName and LineNumber, the values are null. For things like MethodName and ClassName, the value is there but wrong.
I would crash my project with code such as this:
public class TestController : Controller
{
[HttpGet]
[AllowAnonymous]
public string ErrorHandling()
{
var a = int.Parse("fail parsing on purpose");
return a.ToString();
}
}
The value for MethodName ends up being StringToNumber and for ClassName is System.Number
I can't seem to find any information on the web as to why this is and how I can go about retrieving the details for the exception.
EDIT:
I thought it might also be useful to list how I am handling exceptions. I have written a custom middleware error exception handler very similar to the one in this SO post:
https://stackoverflow.com/a/48625298/2371128
EDIT 2:
This is being run in DEBUG mode.
Add the following to your Startup.cs
app.UseExceptionHandler(
options =>
{
options.Run(
async context =>
{
var ex = context.Features.Get<IExceptionHandlerFeature>();
if (ex != null)
{
try
{
await System.Threading.Tasks.Task.Run(async () =>
{
var builder = new DbContextOptionsBuilder<DBContext>();
builder.UseSqlServer(_config["ConnectionStrings:ContextConnection"]);
var _context = new DBContext(_config, builder.Options, httpContextAccessor);
//Log to DB
await repository.LogError(_context, ex.Error.Message, $"{ex.Error.InnerException?.Message}<br/>{ex.Error.StackTrace}");
});
}
finally
{
//Optional
await repository.SendMailToAdmin(ex.Error.Message, $"{ex.Error.InnerException?.Message}<br/>{ex.Error.StackTrace}");
}
context.Response.Redirect("/app/Errors/500");
}
});
}
);
//ErrorLog.cs
public class ErrorLog
{
public int Id { get; set; }
[Required]
[StringLength(500)]
public string Error { get; set; }
[Required]
[StringLength(4000)]
public string Details { get; set; }
public int? UserId { get; set; }
public int CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
}
Here is my suggestion:
public class ExceptionDetail
{
public string Message { get; set; }
public string InnerExceptionMessage { get; set; }
public string StackTrace { get; set; }
public IEnumerable<string> StackTraceLines { get; set; }
public string Target { get; set; }
public string Source { get; set; }
}
var exDetail = new ExceptionDetail
{
Message = exception.Message,
InnerExceptionMessage = exception.InnerException?.Message,
Source = exception.Source,
StackTrace = exception.StackTrace,
StackTraceLines = exception.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(),
Target = exception.TargetSite.ToString()
};
How would you form your parameters for the action method which is supposed to receive one file and one text value from the request?
I tried this
public string Post([FromBody]string name, [FromBody]IFormFile imageFile)
And tried hitting it from Postman but it gives me 500 Internal Server Error. I also can't debug it because it never hits the first statement inside the action method where I've put my breakpoint.
Any idea how can we parse boundary based requests and extract file(s) and other textual field(s)? I am new to ASP.NET Core.
I had the similar issue and I solved the problem by using [FromForm] attribute and FileUploadModelView in the function as follow:
[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload([FromForm] FileUploadViewModel model, [FromForm] string member_code)
{
var file = model.File;
// ...
}
This is a quick solution for anyone who is facing the same issue:
You will use ajax to send the following formData
let formData: FormData;
formData = new FormData();
formData.append('imageFile', imageFile);
formData.append('name', name);
Then you will receive it in your controller like this:
public string Post(IFormCollection data, IFormFile imageFile)
Then you will access the data as you do normally:
var name = data["name"];
In HomeController.cs
using Microsoft.AspNetCore.Hosting;
.......
private IHostingEnvironment _environment;
public HomeController(IHostingEnvironment environment)
{
_environment = environment;
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(IFormCollection formdata)
{
var files = HttpContext.Request.Form.Files;
foreach (var file in files)
{
var uploads = Path.Combine(_environment.WebRootPath, "Images");
if (file.Length > 0)
{
string FileName = Guid.NewGuid(); // Give file name
using (var fileStream = new FileStream(Path.Combine(uploads, FileName), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
}
In view - Index.cshtml
<form method="post" enctype="multipart/form-data" >
.....
</form>
You can try this code.
Thanks!!
I'm using the following code to accomplish this in order to parse a response from Mailgun, which comprises both files and text values.
Please note that "dashifying" is just so property names like "MessageHeaders" get turned into "message-headers"; obviously you should use whatever logic makes sense for your use case.
Controller:
using System;
using Microsoft.AspNetCore.Mvc;
using NuGet.Protocol.Core.v3;
namespace Potato
{
[Route("api/[controller]")]
public class MailgunController : Controller
{
[HttpPost]
public IActionResult Post()
{
MailgunEmail email = new MailgunEmail(Request);
return Ok(email.ToJson());
}
}
}
Model:
using System;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Potato
{
public class MailgunEmail
{
public IEnumerable<IFormFile> Attachments { get; set; }
public string Recipient { get; set; }
public string Sender { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string BodyPlain { get; set; }
public string StrippedText { get; set; }
public string StrippedSignature { get; set; }
public string BodyHtml { get; set; }
public string StrippedHtml { get; set; }
public int? AttachmentCount { get; set; }
public int Timestamp { get; set; }
public string Token { get; set; }
public string Signature { get; set; }
public string MessageHeaders { get; set; }
public string ContentIdMap { get; set; }
public MailgunEmail(HttpRequest request)
{
var form = request.Form;
Attachments = new List<IFormFile>(form.Files);
foreach (var prop in typeof(MailgunEmail).GetProperties()) {
string propName = Dashify(prop.Name);
var curVal = form[propName];
if (curVal.Count > 0) {
prop.SetValue(this, To(curVal[0], prop.PropertyType), null);
}
}
}
private object To(IConvertible obj, Type t)
{
Type u = Nullable.GetUnderlyingType(t);
if (u != null) {
return (obj == null) ? GetDefaultValue(t) : Convert.ChangeType(obj, u);
} else {
return Convert.ChangeType(obj, t);
}
}
private object GetDefaultValue(Type t)
{
if (t.GetTypeInfo().IsValueType) {
return Activator.CreateInstance(t);
}
return null;
}
private string Dashify(string source)
{
string result = "";
var chars = source.ToCharArray();
for (int i = 0; i < chars.Length; ++i) {
var c = chars[i];
if (i > 0 && char.IsUpper(c)) {
result += '-';
}
result += char.ToLower(c);
}
return result;
}
}
}
This page helped me a lot https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads
so now in my code I have the controller method as:
public async Task<IActionResult> UploadFiles(UploadedFile ups)
and a class for the model as
public class UploadedFile
{
public string UploadName { get; set; }
public List<IFormFile> Files { get; set; }
}
and the form like
<form method="post" enctype="multipart/form-data" asp-controller="Files" asp-action="UploadFiles">
I wanted to send a complex object rather than a text value. And can do it like below as well.
Sending form data:
let data = new FormData();
data.append("file", file, file.name);
data.append("someData", JSON.stringify(someData));
Using form data in the controller:
public async Task<IActionResult> OnPostUploadAsync( IFormCollection data )
{
var files = data.Files;
if (data.TryGetValue("someData", out var someData))
{
//use files & some data (json string)
}
}
You Can Get Multi Images By Sample Code Through MultiPart.
First Inject IHttpContextAccessor To ConfigureService Method In
Startup Class.Then Call It With Constructor Injection In
Controller:
private readonly IHttpContextAccessor _httpContextAccessor;
public FileController(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
Action Method Can Have Response Or Not.
public async Task<object> UploadImage()
{
var fileBytes = new List<byte[]>();
var files =
_httpContextAccessor.HttpContext.Request.Form.Files;
foreach (var file in files)
{
if (file.Length > 0)
{
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
fileBytes.Add(memoryStream.ToArray());
}
}
}
// TODO: Write Code For Save Or Send Result To Another Services For Save
}
With the usual controller (.NET 5\6) code will look like this
[ApiController]
[Route("[controller]")]
public class UploadController : Controller
{
[HttpPost]
[Route("CreateUser")]
public async Task<IActionResult> CreateUser([FromForm]ApplicationUserCreationDto userCreationDto)
{
return Json(new
{
user = userCreationDto.UserName,
fileName = userCreationDto.Photo.FileName
});
}
}
public class ApplicationUserCreationDto
{
[Required]
public string UserName { get; set; }
public IFormFile Photo { get; set; }
}
With Minimal API
it depends on the .NET version, as native support for IFormFile/IFormFileCollection is available only with .NET 7
binding from form values is not supported anyway
I propose to use another workaround
I guess you're transmitting the file and text in proper JSON format.
You should create a new class which includes file and text as properties of type string. Add the new class to your method arguments with attribute[FromBody] and you'll be able to parse the image string according to your needs.
Another way would be accessing the whole request content via
await Request.Content.ReadAsStringAsync();
You would then have to parse the entire content, though.
I am trying to build a site using ASP.NET MVC 4 and C# to search for the top 5 albums of a musical artist using the Spotify web api.
Here is my code so far:
public ActionResult Result(string Artist)
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://api.spotify.com/");
// what goes here to authenticate and get the info?
return View();
}
I can not find information that tells me how to authenticate and then retrieve the information using C#.
Edit: I should mention that I am an absolute beginner with this stuff and while I did read the spotify api reference, it did not help me because it does not explain enough detail.
For example the web api user guide talks about GET, POST, etc but does not give any code to help explain how to use it. The only code on there is:
$ curl -H "Authorization: Basic Yjc...cK" -d grant_type=refresh_token -d refresh_token=AQD...f0 "https://accounts.spotify.com/api/token"
{
"error": "invalid_client",
"error_description": "Invalid client secret"
}
Which is confusing to me because I don't know where to put it, I don't know what language the code is, etc.
There are no C# examples that I can find. Even the code examples are all javascript which does not help me.
You should see this maybe help to you
TagSearch
using System;
using System.Net;
using System.Text;
using System.Linq;
using System.Collections.Generic;
namespace TagSearch.Plugins
{
public class Spotify : IClass
{
#region JsonParseData
public class Rootobject
{
public Tracks tracks { get; set; }
}
public class Tracks
{
public List<Item> items { get; set; }
}
public class Item
{
public Album album { get; set; }
public List<Artist> artists { get; set; }
public int disc_number { get; set; }
public string name { get; set; }
public int track_number { get; set; }
}
public class Album
{
public string href { get; set; }
public string release_date { get; set; }
public string release_date_precision { get; set; }
public List<Image> images { get; set; }
public string name { get; set; }
}
public class Image
{
public int height { get; set; }
public string url { get; set; }
public int width { get; set; }
}
public class Artist
{
public string name { get; set; }
}
#endregion
protected Dictionary<String, int> _TempTotal;
protected Dictionary<String, List<ITag>> _TempTag;
private object _Lock = new object();
public Spotify()
{
JParse = new System.Text.Json.JsonParser();
_TempTotal = new Dictionary<string, int>();
_TempTag = new Dictionary<String, List<ITag>>();
}
public override void Search(string Name)
{
GetInfo(Name);
}
protected override void GetInfo(string Name)
{
lock (_Lock)
{
_TempTotal.Add(Name, -1);
_TempTag.Add(Name, new List<ITag>());
}
var web = new IWebClient();
web.DownloadDataCompleted += DownloadDataCompleted;
web.DownloadDataAsync(new Uri("https://api.spotify.com/v1/search?&type=track&limit=50&q=" + Uri.EscapeDataString(Name.ToLower())), new IWebClient.WebClientState(Name, 1, null));
while (_TempTotal[Name] != _TempTag[Name].Count) { System.Threading.Thread.Sleep(1000); }
OnEvent(Name,_TempTag[Name]);
_TempTotal.Remove(Name);
_TempTag.Remove(Name);
base.GetInfo(Name);
}
protected void DownloadDataCompleted(dynamic sender, dynamic e)
{
if (e.Result != null)
{
string Name = e.UserState.Name;
switch ((int)e.UserState.State)
{
case 1:
var _RootObject = JParse.Parse<Rootobject>(Encoding.UTF8.GetString(e.Result));
_TempTotal[Name] = _RootObject.tracks.items.Count;
foreach (var Json in _RootObject.tracks.items)
{
var web = new IWebClient();
web.DownloadDataCompleted += DownloadDataCompleted;
web.DownloadDataAsync(new Uri(Json.album.href), new IWebClient.WebClientState(Name, 2, new ITag(this.GetType(), Json.name, Json.album.name, Json.artists[0].name, null, DateTime.MinValue, Json.disc_number, Json.track_number)));
System.Threading.Thread.Sleep(250);
}
sender.Dispose();
break;
case 2:
var Json2 = JParse.Parse<Album>(System.Text.Encoding.UTF8.GetString(e.Result));
e.UserState.State = 3;
switch ((string)Json2.release_date_precision)
{
case "year": e.UserState.Tag.RelaseDate = DateTime.Parse(Json2.release_date + "-01-01"); break;
case "month": e.UserState.Tag.RelaseDate = DateTime.Parse(Json2.release_date + "-01"); break;
case "day": e.UserState.Tag.RelaseDate = DateTime.Parse(Json2.release_date); break;
}
sender.DownloadDataAsync(new Uri(Json2.images[0].url), e.UserState);
break;
case 3:
e.UserState.Tag.Cover = e.Result;
_TempTag[Name].Add(e.UserState.Tag);
sender.Dispose();
break;
}
}
}
}
}