File upload .NET Core 'IFormFile' does not contain a definition for 'SaveAsASync' and no extension method - file-upload

I'm trying to upload a file using ASP.NET Core Web Api.
As many i found this code:
namespace ModelBindingWebSite.Controllers
{
public class HomeController : Controller
{
private IHostingEnvironment _environment;
public HomeController(IHostingEnvironment environment)
{
_environment = environment;
}
public IActionResult Index()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Index(ICollection<IFormFile> files)
{
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
foreach (var file in files)
{
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
await file.SaveAsAsync(Path.Combine(uploads, fileName));
}
}
return View();
}
}
I get the error IFormFile does not contain a definition for SaveAsASync and no extension method.
Any idea?

You can simply build a handy extension for later use
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
public static class FileSaveExtension
{
public static async Task SaveAsAsync(this IFormFile formFile, string filePath)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await formFile.CopyToAsync(stream);
}
}
public static void SaveAs(this IFormFile formFile, string filePath)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
formFile.CopyTo(stream);
}
}
}
Implementation:
formFile.SaveAsAsync("Your-File-Path"); // [ Async call ]
formFile.SaveAs("Your-File-Path");

Please see https://github.com/aspnet/HttpAbstractions/issues/610 which explains why the method has been superceded

Related

Blazor: How to pass multiple parameter's from NavigateTo to a WEB API controller to download a file

I'm trying to use NavivgateTo in Blazor to pass a file id and name to download a file from my Download controller.
What is the proper setup? I've tried a number of possibilities and I keep seeing an error: Sorry, there is nothing at this address.
Razor Page
public async Task SelectedDisplayDbItemChanged(DisplayDbItemsComboBoxItemDTO item)
{
Data = null;
Data = GetDataTable();
var fileId = await utilities.ExportDataTableToFile((DataTable)Data).ConfigureAwait(false);
//navigationManager.NavigateTo($"api/download/fileId/" + fileId + "/fileName/" + "myfile", true);
//?data1=678&data2=c-sharpcorner
navigationManager.NavigateTo($"api/Download/{fileId}/{"myfile"}", true);
}
Controller:
[HttpPost("Download/{fileId}/{fileName}")]
public async Task<IActionResult> Download(string fileId, string fileName)
{
using (var ms = new MemoryStream())
{
var fullPath = Path.Combine(DownloadPath, fileId);
await using (var stream = new FileStream(fullPath, FileMode.Open))
{
await stream.CopyToAsync(ms);
}
ms.Position = 0;
return File(ms, "application/octet-stream", $"{fileName}.xlsx");
}
}
I've seen a lot of examples from the Razor page to the Razor page, but not from NavigateTo to a controller with passing multiple parameters.
I've tried these responses as well: https://stackoverflow.com/a/71130256/9594249
https://stackoverflow.com/a/71130256/9594249
Not like Asp.net MVC or razor page, in Blazor parameters are passed by [Parameter] tag
#page "/Download/{fileId}/{fileName}"
#code {
[Parameter]
public string? fileId { get; set; }
[Parameter]
public string? fileName { get; set; }
}
please refer : https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-6.0
(Updated)
add to Program.cs or Startup.cs:
builder.Services.AddRazorPages(options => {
options.Conventions.AddPageRoute("/DownloadPage", "Download/{fileId?}/{fileName?}");
}
});
Pages/DownloadPage.cshtml
#page "{fileId?}/{fileName?}"
#model BlazorApp.Pages.DownloadModel
Pages/DownloadPage.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace BlazorApp.Pages;
public class DownloadModel : PageModel
{
private readonly IWebHostEnvironment _env;
public DownloadModel(IWebHostEnvironment env)
{
_env = env;
}
public IActionResult OnGet()
{
// work with RouteData.Values["fileId"] and RouteData.Values["fileName"]
}
}
please refer :
https://learn.microsoft.com/en-us/answers/questions/243420/blazor-server-app-downlaod-files-from-server.html
https://learn.microsoft.com/ko-kr/aspnet/core/razor-pages/razor-pages-conventions?view=aspnetcore-6.0

Aggregate Exception Asp.Net Core 5.0

I have an Mvc project which is based on Asp.Net Core 5.0 . I have my own Core Layer and i have my own Photo,Video uploader method which is based my FileRepo class.
Here is my FileModel class:
public class FileModel
{
public int FileID { get; set; }
public string FileName { get; set; }
public string FileType { get; set; }
public string FileExtension { get; set; }
public string FileSlug { get; set; }
public string FilePath { get; set; }
public byte[] Data { get; set; }
}
Here is my File Uploader method :
public interface IFileUploader
{
Task<FileModel> FileUploadToDatabase(List<IFormFile> files);
Task<FileModel> FileUploadToPath(List<IFormFile> files);
Task<bool> FileDeleteFromPath(int id);
}
public class FileUploader : IFileUploader
{
private FileModel _fileModel;
public FileUploader(FileModel fileModel)
{
_fileModel = fileModel;
}
public async Task<FileModel> FileUploadToDatabase(List<IFormFile> files)
{
foreach (var file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
var extension = Path.GetExtension(file.FileName);
_fileModel = new FileModel
{
FileName = fileName,
FileType = file.ContentType
};
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
_fileModel.Data = dataStream.ToArray();
}
}
return _fileModel;
}
public async Task<FileModel> FileUploadToPath(List<IFormFile> files)
{
foreach (var file in files)
{
var basePath = Path.Combine(Directory.GetCurrentDirectory() + "\\Files\\");
bool basePathExists = Directory.Exists(basePath);
if (!basePathExists) Directory.CreateDirectory(basePath);
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
var filePath = Path.Combine(basePath, file.FileName);
var extension = Path.GetExtension(file.FileName);
if (!File.Exists(filePath))
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
_fileModel = new FileModel
{
FileName = fileName,
FileType = file.ContentType,
FilePath = filePath
};
}
}
return _fileModel;
}
}
As u guys can see,its a different layer and there is nothing related with my Mvc project.
Im getting error when i add those extension to my Mvc project.
The error says me that :
'Some services are not able to be constructed (Error while validating the service descriptor
'ServiceType: CORE_HBKSOFTWARE.Interfaces.IFileUploader Lifetime: Singleton ImplementationType:
CORE_HBKSOFTWARE.Classes.FileUploader': Unable to resolve service for type
'CORE_HBKSOFTWARE.Models.FileModel' while attempting to activate
'CORE_HBKSOFTWARE.Classes.FileUploader'.)'
I dont know why im getting that error. That FileModel class is seems to okey to me and i still dont know. I allready add my services.AddSingleton<IFileUploader, FileUploader>(); to my Startup.cs .
Thanks for any suggestion !
If you want to use constructor injection to create an instance of FileModel in your FileUploader class you need to register it to the IoC Container. You do that by calling following method in the ConfigureServices method:
services.AddSingleton<FileModel>();
You can also choose a different lifetime by calling AddScoped or AddTransient.

Can't run tests for a controller doing Entity Framework Core operations in xUnit

I can't run tests for a controller doing Entity Framework Core operations in xUnit. I am using in-memory database and the error I am getting is:
**A test class may only define a single public constructor.**
The test class is:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyAppT.Controllers;
using MyAppT.Models;
using Xunit;
namespace TestingProject
{
public class TestRegistration
{
#region Seeding
protected TestRegistration(DbContextOptions<AppDbContext> contextOptions)
{
ContextOptions = contextOptions;
Seed();
}
protected DbContextOptions<AppDbContext> ContextOptions { get; }
private void Seed()
{
using (var context = new AppDbContext(ContextOptions))
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var one = new Register()
{
Name = "Test One",
Age = 40
};
var two = new Register()
{
Name = "Test Two",
Age = 50
};
var three = new Register()
{
Name = "Test Three",
Age = 60
};
context.AddRange(one, two, three);
context.SaveChanges();
}
}
#endregion
[Fact]
public void Test_Create_GET_ReturnsViewResultNullModel()
{
using (var context = new AppDbContext(ContextOptions))
{
// Arrange
var controller = new RegistrationController(context);
// Act
var result = controller.Create();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
Assert.Null(viewResult.ViewData.Model);
}
}
}
}
The controller that is doing EF core operations is:
using Microsoft.AspNetCore.Mvc;
using MyAppT.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyAppT.Controllers
{
public class RegistrationController : Controller
{
private AppDbContext context;
public RegistrationController(AppDbContext appDbContext)
{
context = appDbContext;
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create(Register register)
{
if (ModelState.IsValid)
{
context.Add(register);
await context.SaveChangesAsync();
return RedirectToAction("Read");
}
else
return View();
}
}
}
The strange error while running the test shows up in Test Explorer - A test class may only define a single public constructor.
I could not find anything about it on stackoverflow. Please help in fixing it?
Your constructor needs to be parameterless for this to work, unless you're using some DI framework within your testing project, which is something that you generally shouldn't be doing.
Instead, try creating the DBContextOptions within the constructor and assigning it to your class variable. You can then use it when you seed the database, and when you test against it.
Try this instead. You will need to add the Microsoft.EntityFrameworkCore.InMemory package into your test project if you don't have this in there already.
public class TestRegistration
{
#region Seeding
public TestRegistration()
{
ContextOptions = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "Test")
.Options;
Seed();
}

How to invoke a View Component from controller

Is it possible to invoke a View Component from controller and render it to a string? I am really looking for some code example for this. Any help will be much appreciated.
As of beta7 it is now possible to return a ViewComponent directly from a controller. Check the MVC/Razor section of the announcement
The new ViewComponentResult in MVC makes it easy to return the result
of a ViewComponent from an action. This allows you to easily expose
the logic of a ViewComponent as a standalone endpoint.
So now the code for returning the sample view component just needs to be:
public class HomeController : Controller
{
public IActionResult Index()
{
return ViewComponent("My");
}
}
Please refer to example from official ASP.NET article on ViewComponent
In their example, the view component is called directly from the controller as follows:
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
You can do that but you have to apply following thing as It is render by DefaultViewComponentHelper.
You have to create instance of this and to create that you need IViewComponentSelector and IViewComponentInvokerFactory.
To do this I have done following thing.
public class HomeController : Controller
{
Microsoft.AspNet.Mvc.DefaultViewComponentHelper helper = null;
Microsoft.AspNet.Mvc.Razor.RazorView razorView = null;
public HomeController(IViewComponentSelector selector,IViewComponentInvokerFactory factory,IRazorPageFactory razorPageFactory,IRazorPageActivator pageActivator,IViewStartProvider viewStartProvider)
{
helper = new DefaultViewComponentHelper(selector, factory);
razorView = new Microsoft.AspNet.Mvc.Razor.RazorView(razorPageFactory, pageActivator, viewStartProvider);
}
public IActionResult Index()
{
ViewContext context = new ViewContext(ActionContext, razorView, ViewData, null);
helper.Contextualize(context);
string st1 = helper.Invoke("My", null).ToString();
return View();
}
}
Here is my sample View Component.
public class MyViewComponent : ViewComponent
{
public MyViewComponent()
{
}
public IViewComponentResult Invoke()
{
return Content("This is test");
}
}
Here's a tag helper that I created to embed components via HTML like syntax. Invoking from a TagHelper like this should closely match invoking from a Controller.
ViewComponent Tag Helper
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewComponents;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace TagHelperSamples.Web
{
[HtmlTargetElement("component")]
public class ComponentTagHelper : TagHelper
{
private DefaultViewComponentHelper _componentHelper;
[HtmlAttributeName("name")]
public string Name { get; set; }
[HtmlAttributeName("params")]
public object Params { get; set; }
[ViewContextAttribute] // inform razor to inject
public ViewContext ViewContext { get; set; }
public ComponentTagHelper(IViewComponentHelper componentHelper)
{
_componentHelper = componentHelper as DefaultViewComponentHelper;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
_componentHelper.Contextualize(ViewContext);
output.Content.AppendHtml(
await _componentHelper.InvokeAsync(Name, Params)
);
}
}
}
Usage
<component name="RecentComments" params="new { take: 5, random: true }"></component>
Code from dotnetstep's answer updated for MVC 6.0.0-beta4 (VS2015 RC):
public class HomeController : Controller
{
Microsoft.AspNet.Mvc.ViewComponents.DefaultViewComponentHelper helper = null;
public HomeController(IViewComponentDescriptorCollectionProvider descriptorProvider, IViewComponentSelector selector, IViewComponentInvokerFactory invokerFactory)
{
helper = new DefaultViewComponentHelper(descriptorProvider, selector, invokerFactory);
}
public IActionResult Index()
{
ViewContext context = new ViewContext(ActionContext, null, ViewData, null, null);
helper.Contextualize(context);
string st1 = helper.Invoke("My", null).ToString();
return View();
}
}
Based on https://gist.github.com/pauldotknopf/b424e9b8b03d31d67f3cce59f09ab17f
public class HomeController : Controller
{
public async Task<string> RenderViewComponent(string viewComponent, object args)
{
var sp = HttpContext.RequestServices;
var helper = new DefaultViewComponentHelper(
sp.GetRequiredService<IViewComponentDescriptorCollectionProvider>(),
HtmlEncoder.Default,
sp.GetRequiredService<IViewComponentSelector>(),
sp.GetRequiredService<IViewComponentInvokerFactory>(),
sp.GetRequiredService<IViewBufferScope>());
using (var writer = new StringWriter())
{
var context = new ViewContext(ControllerContext, NullView.Instance, ViewData, TempData, writer, new HtmlHelperOptions());
helper.Contextualize(context);
var result = await helper.InvokeAsync(viewComponent, args);
result.WriteTo(writer, HtmlEncoder.Default);
await writer.FlushAsync();
return writer.ToString();
}
}
}
and
public class NullView : IView
{
public static readonly NullView Instance = new();
public string Path => string.Empty;
public Task RenderAsync(ViewContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return Task.CompletedTask;
}
}

Ninject Interception not working with MVC 5

I am trying to implement an InterceptAttribute which should intercept any method I add the attribute to. I have it working in a WebAPI solution, however, I cannot get it to work in an MVC 5 application. The code is the same in both projects. The following code is the attribute I created.
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Attributes;
using Ninject.Extensions.Interception.Request;
namespace Questionnaire.Common.InterceptAttributes
{
public class InterceptCacheAttribute : InterceptAttribute
{
public double TimeOut { get; set; }
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
var cacheInterceptor = request.Kernel.Get<CacheInterceptor>();
cacheInterceptor.TimeOut = TimeOut;
return cacheInterceptor;
}
}
}
The CacheInterceptor code is as follows:
using System;
using System.Text;
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Request;
namespace Questionnaire.Common.Interceptors
{
public class CacheInterceptor : IInterceptor
{
[Inject]
public ICaching Cache { get; set; }
public double TimeOut { get; set; }
public void Intercept(IInvocation invocation)
{
var minutes = Cache.TimeOutMinutes;
if (Math.Abs(TimeOut - default(double)) > 0)
{
minutes = TimeOut;
}
invocation.ReturnValue = Cache.Get(GenerateCacheKey(invocation.Request), minutes, delegate
{
invocation.Proceed();
return invocation.ReturnValue;
});
}
private static string GenerateCacheKey(IProxyRequest request)
{
var sb = new StringBuilder(request.Method.Name).Append(".");
foreach (var argument in request.Arguments)
{
if (argument == null)
{
sb.Append("null");
}
else if (argument is string && argument.ToString().Length < 50)
{
sb.Append((string)argument);
}
else
{
sb.Append(argument.GetHashCode());
}
sb.Append(".");
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
}
}
Finally I added the attribute to the following method.
using System.Configuration;
using Questionnaire.Common.InterceptAttributes;
namespace Questionnaire.Common.Utility
{
public class ConfigurationUtilities
{
[InterceptCache(TimeOut = 1440)]
public virtual string GetEnvironmentConnectionString(string name)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[name + "_" + HostEnvironment];
return connectionStringSettings != null ? connectionStringSettings.ConnectionString : null;
}
}
}
Code execution never enters into the InterceptCacheAttribute class. I have put debug points within that class and the CacheInterceptor class and the debug points are never hit. The method the attribute is on executes just fine, but, I want it to be intercepted and that is not happening. I have the same code in a different project. That project is a WebAPI project which works great. The methods are intercepted and everything functions as it should. Can someone explain to me why I can't get it to work in the MVC 5 application? I would greatly appreciate it.
answer to BatteryBackupUnit's question:
The answer is I can't. The following is my NinjectWebCommon.cs class.
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Mayo.Questionnaire.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Mayo.Questionnaire.App_Start.NinjectWebCommon), "Stop")]
namespace Questionnaire.App_Start
{
using System;
using System.Web;
using System.Web.Http;
using System.Linq;
using ApplicationExtensions;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
foreach (var module in from assembly in AppDomain.CurrentDomain.GetAssemblies()
select assembly.GetNinjectModules()
into modules
from module in modules
where !kernel.GetModules().Any(m => m.Name.Equals(module.Name))
select module)
{
kernel.Load(module);
}
}
}
}
Inside the RegisterServices method every assembly in the application is iterated over and any classes that inherit from NinjectModule are loaded. However, I can't verify that it is working because I can't debug it. I have tried, but, execution is never stopped within the class. I know that the class is being instantiated and that the modules are being loaded because I have bindings in those modules that are working, however, I can't verify it.