Display an array of images from Azure Blobs with .Net6 - c#

I am a junior front-end developer, and I got a task where I have to take an Azure Blobs Container lets call it "thumbnails" , loop through and display it on the screen using .Net 6.
Basically, I have to make an image gallery in Dotnet 6 that takes the images from the Blob Container with DotNet6, add it to the View (MVC) and list it with AngularJS but many of my attempts has failed.
Made a small example in case if it is not clear what I want to achieve:
Image
My questions are:
How can I take data from Azure Storage with .net 6?
How can I create an array from it and pass it to the View?

you need to use the nugget Azure.Storage.Blobs. This package exposes many methods you can utilise.
IAsyncEnumerable<BlobItem> blobs = blobContainer.GetBlobsAsync(prefix: "");
await foreach (BlobItem blobItem in blobs)
{
...
}
import the using System.Linq.Async for this to work.
Check the official docs to see more details on constructing the blobContainer.
You can extract the base64 string value from the blobs and bind it in the UI directly.

In MVC
Controller:
using System.Configuration;
using System.IO;
using System.Threading.Tasks;
using System.Web;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Microsoft.AspNetCore.Mvc;
public class HomeController : Controller
{
const string blobContainerName = "tnail";
static BlobContainerClient blobContainer;
private IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task<ActionResult> Index()
{
try
{
var s = _configuration.GetConnectionString("AConnectionString");
BlobServiceClient blobServiceClient = new BlobServiceClient(s);
blobContainer = blobServiceClient.GetBlobContainerClient(blobContainerName);
await blobContainer.CreateIfNotExistsAsync(PublicAccessType.Blob);
List<Uri> allBlobs = new List<Uri>();
foreach (BlobItem blob in blobContainer.GetBlobs())
{
if (blob.Properties.BlobType == BlobType.Block)
allBlobs.Add(blobContainer.GetBlobClient(blob.Name).Uri);
}
return View(allBlobs);
}
catch (Exception ex)
{
ViewData["message"] = ex.Message;
ViewData["trace"] = ex.StackTrace;
return View("Error");
}
}
Model:
namespace AzureBlobLearning.Models
{
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
appsetting.json:
Add Connectionstring data that you can find it the Azure portal, with the name of AConnectionString
View:
#if (Model != null && Model.Count > 0)
{
foreach (var item in Model)
{
<div class="imageBlock">
<img class="thumb" src="#item" alt="images"/><br />
<div class="deleteDiv"><img class="deleteIcon" src="~/Images/deleteImage.png" title="Delete Image" onclick="deleteImage('#item');" /></div>
</div>
}
}
See Sample: https://github.com/Azure-Samples/storage-blobs-dotnet-webapp

Related

.Net 6 Code doesn't display in implemented large project

I am working in a larger project, but because it is very complex I made my own small project to make an Azure Blobs Gallery, that displays images from Azure Blobs using container, to implement into the large project after that.
I was able to create this Gallery with the following .Net 6 / C# (MVC) code:
Controller
public class ResourceController : Controller
{
const string blobContainerName = "thumbnails";
static BlobContainerClient blobContainer;
private IConfiguration _configuration;
public ResourceController(IConfiguration configuration)
{
_configuration = configuration;
}
public ActionResult Index()
{
var model = LoadModelMethodAsync();
return View(model);
}
public ActionResult Info()
{
var model = LoadModelMethodAsync();
return View(model);
}
public List<Uri> LoadModelMethodAsync()
{
try
{
var s = _configuration.GetConnectionString("AzureStorageConnectionString");
BlobServiceClient blobServiceClient = new BlobServiceClient(s);
blobContainer = blobServiceClient.GetBlobContainerClient(blobContainerName);
blobContainer.CreateIfNotExistsAsync(PublicAccessType.Blob);
List<Uri> allBlobs = new List<Uri>();
foreach (BlobItem blob in blobContainer.GetBlobs())
{
if (blob.Properties.BlobType == BlobType.Block)
allBlobs.Add(blobContainer.GetBlobClient(blob.Name).Uri);
}
return allBlobs;
}
catch (Exception ex)
{
ViewData["message"] = ex.Message;
ViewData["trace"] = ex.StackTrace;
throw;
}
}
}
}
ViewModel
using Microsoft.AspNetCore.Mvc;
namespace EBP_V1.ViewModels {
public class ResourceViewModel
{
public string RequestId { get; set; }
public bool? ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
Partial
#using AzureBlobLearning.Models
#model List<Uri>
#{
}
#if (Model != null && Model.Count > 0)
{
foreach (var item in Model)
{
<div class="imageBlock" value="GetGallery">
<img class="thumb" src="#item" alt="images"/><br />
<div class="deleteDiv"><img class="deleteIcon" src="~/Images/deleteImage.png" title="Delete Image" onclick="deleteImage('#item');" /></div>
</div>
}
}
View: Info.cshtml
<partial name="~/Views/Resource/_ResourcePartial.cshtml"/>
This small project works well, but when I try to implement it in the large project, the page isn't working anymore, even though it doesn't throw any error, and when I try to debug it all the data the same as it was before.
Controller in the large project ( everything else is identical with the previous one)
[HttpGet]
public async Task<ViewResult> Info(Guid? id, string filterTxt )
{
await SetCompanyName(id, filterTxt);
var model = LoadModelMethodAsync();
return View(model);
}
The interesting thing is that even if I don't call the model variable in the View the page still won't work anymore.
Question:
Why my code doesn't work in the large project?
What should I change to make it work?
P.S.:
- I am a completely beginner in .Net 6 / C# world, my first language
is Javascript, so please be understanding.
- If you have any questions, suggestions don't hesitate to ask.

How to pass a Azure Blob Model to another class in .Net 6

I am experiencing with the C#/.Net world using Azure Blobs.
I made a Gallery that takes the images from an Azure Blob Storage, and displays it on the screen.
I want to create a Partial View from it, because of the DRY principle so I could reuse it in other files as well.
When I display the Partial View on the index it works well, but when I try to display it in the Info.cshtml file doesn't find the Model variable.
Controller
public class ResourceController : Controller
{
const string blobContainerName = "blobContainer";
static BlobContainerClient blobContainer;
private IConfiguration _configuration;
public ResourceController(IConfiguration configuration)
{
_configuration = configuration;
}
// Create a List of images using Azure Blobs and Displays it on the Screen.
{
try
{
var s = _configuration.GetConnectionString("AzureConnectionString");
BlobServiceClient blobServiceClient = new BlobServiceClient(s);
blobContainer = blobServiceClient.GetBlobContainerClient(blobContainerName);
await blobContainer.CreateIfNotExistsAsync(PublicAccessType.Blob);
List<Uri> allBlobs = new List<Uri>();
foreach (BlobItem blob in blobContainer.GetBlobs())
{
if (blob.Properties.BlobType == BlobType.Block)
allBlobs.Add(blobContainer.GetBlobClient(blob.Name).Uri);
}
return View(allBlobs);
}
catch (Exception ex)
{
ViewData["message"] = ex.Message;
ViewData["trace"] = ex.StackTrace;
return View("Error");
}
}
public ActionResult Info(){
//This class doesn't see the Model variable
return View();
}
Partial
//The Info class Doesn't see the Model variable
#if (Model != null && Model.Count > 0)
{
foreach (var item in Model)
{
<div class="imageBlock" value="GetGallery">
<img class="thumb" src="#item" alt="images"/><br />
<div class="deleteDiv"><img class="deleteIcon" src="~/Images/deleteImage.png" title="Delete Image" onclick="deleteImage('#item');" /></div>
</div>
}
}
ViewModel
using Microsoft.AspNetCore.Mvc;
namespace AzureBlobLearning.Models
{
public class ResourceViewModel
{
public string? RequestId { get; set; }
public bool? ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
Index.csthml
//This displays the list of images
<partial name="~/Views/Resource/_ResourcePartial.cshtml" />
Info.cshtml
//This doesn't display
<partial name="~/Views/Resource/_ResourcePartial.cshtml" />
My Question:
Why it doesn't see my Info view.
How should I change my code so the Info sees the partialView?
PS.: If you have any questions feel free to ask.
Why it doesn't see my Info view.
Because the action is just returning the View, with no Model inside.
Change from this:
public ActionResult Info(){
//This class doesn't see the Model variable
return View();
}
to this:
public ActionResult Index(){
var model = LoadModelMethod();
return View(model);
}
public ActionResult Info(){
var model = LoadModelMethod();
return View(model);
}
public List<Uri> LoadModelMethod()
{
try
{
var s = _configuration.GetConnectionString("AzureConnectionString");
BlobServiceClient blobServiceClient = new BlobServiceClient(s);
blobContainer = blobServiceClient.GetBlobContainerClient(blobContainerName);
await blobContainer.CreateIfNotExistsAsync(PublicAccessType.Blob);
List<Uri> allBlobs = new List<Uri>();
foreach (BlobItem blob in blobContainer.GetBlobs())
{
if (blob.Properties.BlobType == BlobType.Block)
allBlobs.Add(blobContainer.GetBlobClient(blob.Name).Uri);
}
return allBlobs;
}
catch (Exception ex)
{
ViewData["message"] = ex.Message;
ViewData["trace"] = ex.StackTrace;
throw;
}
}
How should I change my code so the Info sees the partialView?
you can do what I said above, extract the logic which loads the images to a method, and call it in both actions.

How to assign an object, for example, the owner's car [duplicate]

I've done this before with MVC5 using User.Identity.GetUserId() but that doesn't seem to work here.
The User.Identity doesn't have the GetUserId() method.
I am using Microsoft.AspNet.Identity.
Update in ASP.NET Core Version >= 2.0
In the Controller:
public class YourControllerNameController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public YourControllerNameController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<IActionResult> YourMethodName()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier) // will give the user's userId
var userName = User.FindFirstValue(ClaimTypes.Name) // will give the user's userName
// For ASP.NET Core <= 3.1
ApplicationUser applicationUser = await _userManager.GetUserAsync(User);
string userEmail = applicationUser?.Email; // will give the user's Email
// For ASP.NET Core >= 5.0
var userEmail = User.FindFirstValue(ClaimTypes.Email) // will give the user's Email
}
}
In some other class:
public class OtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
public OtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void YourMethodName()
{
var userId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
}
}
Then you should register IHttpContextAccessor in the Startup class as follows:
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Or you can also register as follows
services.AddHttpContextAccessor();
}
For more readability write extension methods as follows:
public static class ClaimsPrincipalExtensions
{
public static T GetLoggedInUserId<T>(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(loggedInUserId, typeof(T));
}
else if (typeof(T) == typeof(int) || typeof(T) == typeof(long))
{
return loggedInUserId != null ? (T)Convert.ChangeType(loggedInUserId, typeof(T)) : (T)Convert.ChangeType(0, typeof(T));
}
else
{
throw new Exception("Invalid type provided");
}
}
public static string GetLoggedInUserName(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue(ClaimTypes.Name);
}
public static string GetLoggedInUserEmail(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue(ClaimTypes.Email);
}
}
Then use as follows:
public class YourControllerNameController : Controller
{
public IActionResult YourMethodName()
{
var userId = User.GetLoggedInUserId<string>(); // Specify the type of your UserId;
var userName = User.GetLoggedInUserName();
var userEmail = User.GetLoggedInUserEmail();
}
}
public class OtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
public OtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void YourMethodName()
{
var userId = _httpContextAccessor.HttpContext.User.GetLoggedInUserId<string>(); // Specify the type of your UserId;
}
}
Until ASP.NET Core 1.0 RC1 :
It's User.GetUserId() from System.Security.Claims namespace.
Since ASP.NET Core 1.0 RC2 :
You now have to use UserManager.
You can create a method to get the current user :
private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(HttpContext.User);
And get user information with the object :
var user = await GetCurrentUserAsync();
var userId = user?.Id;
string mail = user?.Email;
Note :
You can do it without using a method writing single lines like this string mail = (await _userManager.GetUserAsync(HttpContext.User))?.Email, but it doesn't respect the single responsibility principle. It's better to isolate the way you get the user because if someday you decide to change your user management system, like use another solution than Identity, it will get painful since you have to review your entire code.
you can get it in your controller:
using System.Security.Claims;
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
or write an extension method like before .Core v1.0
using System;
using System.Security.Claims;
namespace Shared.Web.MvcExtensions
{
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
}
}
and get wherever user ClaimsPrincipal is available :
using Microsoft.AspNetCore.Mvc;
using Shared.Web.MvcExtensions;
namespace Web.Site.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return Content(this.User.GetUserId());
}
}
}
I included using System.Security.Claims and I could access the GetUserId() extension method
NB: I had the using Microsoft.AspNet.Identity already but couldn't get the extension method. So I guess both of them have to be used in conjunction with one another
using Microsoft.AspNet.Identity;
using System.Security.Claims;
EDIT:
This answer is now outdated. Look at Soren's or Adrien's answer for a dated way of achieving this in CORE 1.0
For .NET Core 2.0 Only The following is required to fetch the UserID of the logged-in User in a Controller class:
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
or
var userId = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
e.g.
contact.OwnerID = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
As stated somewhere in this post, the GetUserId() method has been moved to the UserManager.
private readonly UserManager<ApplicationUser> _userManager;
public YourController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public IActionResult MyAction()
{
var userId = _userManager.GetUserId(HttpContext.User);
var model = GetSomeModelByUserId(userId);
return View(model);
}
If you started an empty project you might need to add the UserManger to your services in startup.cs. Otherwise this should already be the case.
you have to import Microsoft.AspNetCore.Identity & System.Security.Claims
// to get current user ID
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
// to get current user info
var user = await _userManager.FindByIdAsync(userId);
For ASP.NET Core 2.0, Entity Framework Core 2.0, AspNetCore.Identity 2.0 api (https://github.com/kkagill/ContosoUniversity-Backend):
The Id was changed to User.Identity.Name
[Authorize, HttpGet("Profile")]
public async Task<IActionResult> GetProfile()
{
var user = await _userManager.FindByIdAsync(User.Identity.Name);
return Json(new
{
IsAuthenticated = User.Identity.IsAuthenticated,
Id = User.Identity.Name,
Name = $"{user.FirstName} {user.LastName}",
Type = User.Identity.AuthenticationType,
});
}
Response:
In .net core 3.1 (and other more recent versions), you can use:
private readonly UserManager<IdentityUser> _userManager;
public ExampleController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
Then:
string userId = _userManager.GetUserId(User);
Or async:
var user = await _userManager.GetUserAsync(User);
var userId = user.Id;
At this point, I'm trying to figure out why you'd use one over the other. I know the general benefits of async, but see both of these used frequently. Please post some comments if anyone knows.
For ASP.NET 5.0, I have an extension method as follow:
using System;
using System.ComponentModel;
using System.Security.Claims;
namespace YOUR_PROJECT.Presentation.WebUI.Extensions
{
public static class ClaimsPrincipalExtensions
{
public static TId GetId<TId>(this ClaimsPrincipal principal)
{
if (principal == null || principal.Identity == null ||
!principal.Identity.IsAuthenticated)
{
throw new ArgumentNullException(nameof(principal));
}
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(TId) == typeof(string) ||
typeof(TId) == typeof(int) ||
typeof(TId) == typeof(long) ||
typeof(TId) == typeof(Guid))
{
var converter = TypeDescriptor.GetConverter(typeof(TId));
return (TId)converter.ConvertFromInvariantString(loggedInUserId);
}
throw new InvalidOperationException("The user id type is invalid.");
}
public static Guid GetId(this ClaimsPrincipal principal)
{
return principal.GetId<Guid>();
}
}
}
So you can use it like:
using Microsoft.AspNetCore.Mvc;
using YOUR_PROJECT.Presentation.WebUI.Extensions;
namespace YOUR_PROJECT.Presentation.WebUI.Controllers
{
public class YourController :Controller
{
public IActionResult YourMethod()
{
// If it's Guid
var userId = User.GetId();
// Or
// var userId = User.GetId<int>();
return View();
}
}
}
in the APiController
User.FindFirst(ClaimTypes.NameIdentifier).Value
Something like this you will get the claims
Although Adrien's answer is correct, you can do this all in single line. No need for extra function or mess.
It works I checked it in ASP.NET Core 1.0
var user = await _userManager.GetUserAsync(HttpContext.User);
then you can get other properties of the variable like user.Email. I hope this helps someone.
For getting current user id in razor views, we can inject UserManager in the view like this:
#inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> _userManager
#{ string userId = _userManager.GetUserId(User); }
I hope you find it useful.
User.Identity.GetUserId();
does not exist in asp.net identity core 2.0. in this regard, i have managed in different way. i have created a common class for use whole application, because of getting user information.
create a common class PCommon & interface IPCommon
adding reference using System.Security.Claims
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Common.Web.Helper
{
public class PCommon: IPCommon
{
private readonly IHttpContextAccessor _context;
public PayraCommon(IHttpContextAccessor context)
{
_context = context;
}
public int GetUserId()
{
return Convert.ToInt16(_context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
}
public string GetUserName()
{
return _context.HttpContext.User.Identity.Name;
}
}
public interface IPCommon
{
int GetUserId();
string GetUserName();
}
}
Here the implementation of common class
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Pay.DataManager.Concreate;
using Pay.DataManager.Helper;
using Pay.DataManager.Models;
using Pay.Web.Helper;
using Pay.Web.Models.GeneralViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Pay.Controllers
{
[Authorize]
public class BankController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;
private readonly IPCommon _iPCommon;
public BankController(IUnitOfWork unitOfWork, IPCommon IPCommon, ILogger logger = null)
{
_unitOfWork = unitOfWork;
_iPCommon = IPCommon;
if (logger != null) { _logger = logger; }
}
public ActionResult Create()
{
BankViewModel _bank = new BankViewModel();
CountryLoad(_bank);
return View();
}
[HttpPost, ActionName("Create")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Insert(BankViewModel bankVM)
{
if (!ModelState.IsValid)
{
CountryLoad(bankVM);
//TempData["show-message"] = Notification.Show(CommonMessage.RequiredFieldError("bank"), "Warning", type: ToastType.Warning);
return View(bankVM);
}
try
{
bankVM.EntryBy = _iPCommon.GetUserId();
var userName = _iPCommon.GetUserName()();
//_unitOfWork.BankRepo.Add(ModelAdapter.ModelMap(new Bank(), bankVM));
//_unitOfWork.Save();
// TempData["show-message"] = Notification.Show(CommonMessage.SaveMessage(), "Success", type: ToastType.Success);
}
catch (Exception ex)
{
// TempData["show-message"] = Notification.Show(CommonMessage.SaveErrorMessage("bank"), "Error", type: ToastType.Error);
}
return RedirectToAction(nameof(Index));
}
}
}
get userId and name in insert action
_iPCommon.GetUserId();
Thanks,
Maksud
TLDR:
In the Controler add:
using System.Security.Claims;
and then you can use:
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
endof TLDR;
Just an easy way in dot net 6 to test how to get the userID and test it in the default Blazor WebAssembly Core Hosted:
I added a String in WeatherForecast class named userId
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string userId { get; set; } = "nope";
}
Then in the WeatherForecastController
I add
using System.Security.Claims;
In the GET method I set WeatherForecast.userId to User.FindFirstValue(ClaimTypes.NameIdentifier):
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)],
userId = User.FindFirstValue(ClaimTypes.NameIdentifier)
})
.ToArray();
}
And finally in the FetchData.razor I modify the table to:
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
<th>User Id</th>
</tr>
</thead>
<tbody>
#foreach (var forecast in forecasts)
{
<tr>
<td>#forecast.Date.ToShortDateString()</td>
<td>#forecast.TemperatureC</td>
<td>#forecast.TemperatureF</td>
<td>#forecast.Summary</td>
<td>#forecast.userId</td>
</tr>
}
</tbody>
</table>
And then finally I get:
I hope it helps because in net core 6 sometimes it's quite difficult to find the answers
If you are using JWT tokens this code works:
User.FindFirstValue("sub");
use can use
string userid = User.FindFirst("id").Value;
for some reason NameIdentifier now retrieve the username (.net core 2.2)
Make sure that you have enable windows authentication. If you have anonymous authentication enabled you may be getting a null string.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio
I know there are many answers posted already, but maybe it will help someone as it did for me.
I mixed two solutions into one, and I am able to get the logged-in User and its Data.
I was using DotNet 5.
Following code, help to get the logged-in User.
var user = await _userManager.FindByNameAsync(HttpContext.User.Identity.Name);
I used the following package for _userManager
using Microsoft.AspNetCore.Identity;
And for HttpContext, I inherit my Controller from ControllerBase, and for ControllerBase Class I was using the following package
using Microsoft.AspNetCore.Mvc;
As an administrator working on other people's profile and you need to get the Id of the profile you are working on, you can use a ViewBag to capture the Id e.g ViewBag.UserId = userId; while userId is the string Parameter of the method you are working on.
[HttpGet]
public async Task<IActionResult> ManageUserRoles(string userId)
{
ViewBag.UserId = userId;
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ErrorMessage = $"User with Id = {userId} cannot be found";
return View("NotFound");
}
var model = new List<UserRolesViewModel>();
foreach (var role in roleManager.Roles)
{
var userRolesViewModel = new UserRolesViewModel
{
RoleId = role.Id,
RoleName = role.Name
};
if (await userManager.IsInRoleAsync(user, role.Name))
{
userRolesViewModel.IsSelected = true;
}
else
{
userRolesViewModel.IsSelected = false;
}
model.Add(userRolesViewModel);
}
return View(model);
}
If you want this in ASP.NET MVC Controller, use
using Microsoft.AspNet.Identity;
User.Identity.GetUserId();
You need to add using statement because GetUserId() won't be there without it.

C#: How to install System.Web

I am using Visual Studio Code version 1.42 on my Ubuntu 18.04. I just successfully installed sudo dotnet add package Google.Apis.Drive.v3 via terminal but I can't find a way to install System.Web on my C# project.
I tried many different ways:
1) sudo dotnet add package Microsoft.AspNet.WebApi
2) sudo dotnet add package Microsoft.AspNet.Mvc -Version 5.2.7
3) sudo dotnet add package Microsoft.AspNet.Mvc
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
//using System.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
namespace IHostingEnvironmentExample.Controllers
{
public class HomeController : Controller
{
private IHostingEnvironment _env;
public HomeController(IHostingEnvironment env)
{
_env = env;
}
public IActionResult Index()
{
var webRoot = _env.WebRootPath;
var file = System.IO.Path.Combine(webRoot, "test.txt");
System.IO.File.WriteAllText(file, "Hello World!");
return View();
}
}
}
namespace WebApi2.Models
{
public class GoogleDriveFilesRepository
{
//defined scope.
public static string[] Scopes = { DriveService.Scope.Drive };
// Operations....
//create Drive API service.
public static DriveService GetService()
{
//Operations....
public static List<GoogleDriveFiles> GetDriveFiles()
{
// Other operations....
}
//file Upload to the Google Drive.
public static void FileUpload(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
DriveService service = GetService();
string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
Path.GetFileName(file.FileName));
file.SaveAs(path);
var FileMetaData = new Google.Apis.Drive.v3.Data.File();
FileMetaData.Name = Path.GetFileName(file.FileName);
FileMetaData.MimeType = MimeMapping.GetMimeMapping(path);
FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
{
request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
request.Fields = "id";
request.Upload();
}
}
}
//Download file from Google Drive by fileId.
public static string DownloadGoogleFile(string fileId)
{
DriveService service = GetService();
string FolderPath = System.Web.HttpContext.Current.Server.MapPath("/GoogleDriveFiles/");
FilesResource.GetRequest request = service.Files.Get(fileId);
string FileName = request.Execute().Name;
string FilePath = System.IO.Path.Combine(FolderPath, FileName);
MemoryStream stream1 = new MemoryStream();
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
SaveStream(stream1, FilePath);
break;
}
case DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream1);
return FilePath;
}
}
}
Post that I consulted to find a solution to this problem were this one, this, also this one.
I came across this too which seemed to be related but no luck.
Also this last one was useful, however I am confused about which type of package to install.
thanks for providing guidance on how to solve this problem.
As per the code you showed, you are trying to use System.Web.HttpContext.Current.Server.MapPath, which indeed does not exist in .NET Core.
There is no more HttpContext static usable in ASP.NET Core, along with System.Web entirely.
To replace the "Server.MapPath", you can follow some guidance here : https://www.mikesdotnetting.com/Article/302/server-mappath-equivalent-in-asp-net-core
Basically, you need to access a IHostingEnvironment env object, that ASP.NET Core will happily inject.
I'd recommend not using static methods to leverage the constructor dependency injection that is performed in controller constructor automatically.
Otherwise you can also call the dependency service to get the instance (all the details of how to use the dependency service is a bit out of scope here, but feel free to comment if this is not clear)
From this, you should be able to get the path of the server :
public class HomeController : Controller
{
private IHostingEnvironment _env;
// Injection of IHostingEnvironment dependency through constructor
public HomeController(IHostingEnvironment env)
{
_env = env;
}
public void MyMethod()
{
// here you get your replacement of "Server.MapPath" :
var serverPath = _env.WebRootPath;
// ...
}
}
See also this related Q&A : How to use IHostingEnvironment

How to have razor find views from another assembly in a template service

I am trying to load a razor view from another project. I have gone down a few different rabbit holes but so far I have not found a way to make this work. However, from my research there seems to be two main ways to get this working.
One option would be to use embedded resources and then hook up an embedded file provider into razor. I might be wrong but I think this is a pre .net core 2.1 approach. My understanding is that, in 2.1 Razor views are compiled at build time. Setting it as embedded would save the actual file which would be useful for the older runtime compiling.
// Add the embedded file provider to be used with razor view templates
var viewAssembly = typeof(CoreStartup).GetTypeInfo().Assembly;
var fileProvider = new EmbeddedFileProvider(viewAssembly);
services.Configure<RazorViewEngineOptions>(o => o.FileProviders.Add(fileProvider));
services.AddTransient<ITemplateService, TemplateService>();
The other approach would be to put the views in an areas folder. I even found a sample project which shows you can do exactly that! However, I have been unable to find a way to get the same results.
For reference here is the service I am trying to use to find and render the razor views. I need to get the html output from it to help create an html email template.
namespace TestApp.Services
{
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
using Serilog;
public class TemplateService : ITemplateService
{
private readonly IServiceProvider _serviceProvider;
private readonly ITempDataProvider _tempDataProvider;
private readonly IRazorViewEngine _viewEngine;
public TemplateService(
IServiceProvider serviceProvider,
ITempDataProvider tempDataProvider,
IRazorViewEngine viewEngine)
{
this._serviceProvider = serviceProvider;
this._tempDataProvider = tempDataProvider;
this._viewEngine = viewEngine;
}
public async Task<string> RenderTemplateAsync<TViewModel>(string viewPath, TViewModel viewModel)
{
var httpContext = new DefaultHttpContext
{
RequestServices = this._serviceProvider
};
return await RenderTemplateAsync(httpContext, viewPath, viewModel);
}
public async Task<string> RenderTemplateAsync<TViewModel>(HttpContext httpContext, string viewPath, TViewModel viewModel)
{
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var viewResult = this._viewEngine.FindView(actionContext, viewPath, false);
if (!viewResult.Success)
{
Log.Error("Failed to render template {#viewPath} because it was not found.", viewPath);
throw new FileNotFoundException($"Failed to render template {viewPath} because it was not found.");
}
var viewDictionary = new ViewDataDictionary<TViewModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
var tempDataDictionary = new TempDataDictionary(httpContext, this._tempDataProvider);
using (var outputWriter = new StringWriter())
{
try
{
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
tempDataDictionary,
outputWriter,
new HtmlHelperOptions());
viewContext.ViewData.Model = viewModel;
await viewResult.View.RenderAsync(viewContext);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to render template due to a razor engine failure");
throw;
}
return outputWriter.ToString().Replace("\r\n", string.Empty);
}
}
}
}
I am calling the service like this. I have tried every possible string I can think of in the route to try and get it to work. The problem is I'm not sure the exact format to use for finding an area view. So I'm not sure if the route is wrong or if it's not hooked up right.
var body = await _templateService.RenderTemplateAsync(HttpContext, "Common/EmailDetails", emailModel);
Right now I'm trying to get the EmailDetails.cshtml shared view.
/Areas
/Common
/Views
/Shared
-EmailDetails.cshtml
Check this please
This is working only for searching views in app directory:
public class MyViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context)
{
}
public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
return viewLocations.Select(f => f.Replace("/Views/", "/Areas/Common/Views/"));
}
}
And in startup class:
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add( new MyViewLocationExpander());
});
If you need load view from "outside" of app, check this: https://www.mikesdotnetting.com/article/301/loading-asp-net-core-mvc-views-from-a-database-or-other-location
You can use IViewLocationExpander. Please see https://weblogs.asp.net/imranbaloch/view-location-expander-aspnet5-mvc6

Categories

Resources