IActionSelectorDecisionTreeProvider namespace could not be found in .Net 5 - .net-core

I want to create an extension method of #Html.Action But Showing Error for IActionSelectorDecisionTreeProvider could not load namespace
var actionSelector = GetServiceOrFail<IActionSelectorDecisionTreeProvider>(currentHttpContext);
Error Screen Short
I have installed all dependencies of dot.net 5 like
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
But No Luck.

Working Code In Dot Net 5
public static class HtmlHelperViewExtensions
{
public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, object parameters = null)
{
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
return RenderAction(helper, action, controller, parameters);
}
public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, object parameters = null)
{
var area = (string)helper.ViewContext.RouteData.Values["area"];
return RenderAction(helper, action, controller, area, parameters);
}
public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
if (action == null)
throw new ArgumentNullException("action");
if (controller == null)
throw new ArgumentNullException("controller");
//if (area == null)
// throw new ArgumentNullException("area");
var task = RenderActionAsync(helper, action, controller, area, parameters);
return task.Result;
}
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
// fetching required services for invocation
var currentHttpContext = helper.ViewContext?.HttpContext;
var httpContextFactory = GetServiceOrFail<IHttpContextFactory>(currentHttpContext);
var actionInvokerFactory = GetServiceOrFail<IActionInvokerFactory>(currentHttpContext);
var actionSelector = GetServiceOrFail<IActionDescriptorCollectionProvider>(currentHttpContext);
// creating new action invocation context
var routeData = new RouteData();
var routeParams = new RouteValueDictionary(parameters ?? new { });
var routeValues = new RouteValueDictionary(new { area = area, controller = controller, action = action });
var newHttpContext = httpContextFactory.Create(currentHttpContext.Features);
newHttpContext.Response.Body = new MemoryStream();
foreach (var router in helper.ViewContext.RouteData.Routers)
routeData.PushState(router, null, null);
routeData.PushState(null, routeValues, null);
routeData.PushState(null, routeParams, null);
var actionDescriptor = actionSelector.ActionDescriptors.Items.Where(i => i.RouteValues["controller"] == controller && i.RouteValues["action"] == action).First();
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
// invoke action and retreive the response body
var invoker = actionInvokerFactory.CreateInvoker(actionContext);
string content = null;
await invoker.InvokeAsync().ContinueWith(task => {
if (task.IsFaulted)
{
content = task.Exception.Message;
}
else if (task.IsCompleted)
{
newHttpContext.Response.Body.Position = 0;
using (var reader = new StreamReader(newHttpContext.Response.Body))
content = reader.ReadToEnd();
}
});
return new HtmlString(content);
}
private static TService GetServiceOrFail<TService>(HttpContext httpContext)
{
if (httpContext == null)
throw new ArgumentNullException(nameof(httpContext));
var service = httpContext.RequestServices.GetService(typeof(TService));
if (service == null)
throw new InvalidOperationException($"Could not locate service: {nameof(TService)}");
return (TService)service;
}
}

Related

hash and salt problem when using IPasswordHasher<User> and BCrypt algorhitm

I faced problem with hashing, salting and verifying password in ASP.NET.
I am creating a new User and then using hashing method.
But when I try to get some resources which requires Authorization and I
enter the same username and password as I saved in database the result is failed.
Here is my password hasher class:
using Microsoft.AspNetCore.Identity;
namespace FlowerShop.ApplicationServices.Components.PasswordHasher
{
public class BCryptPasswordHasher<User> : IPasswordHasher<User> where User : class
{
public string HashPassword(User user, string password)
{
return BCrypt.Net.BCrypt.HashPassword(password, 12);
}
public PasswordVerificationResult VerifyHashedPassword(User user, string hashedPassword, string providedPassword)
{
var isValid = BCrypt.Net.BCrypt.Verify(providedPassword, hashedPassword);
if (isValid && BCrypt.Net.BCrypt.PasswordNeedsRehash(hashedPassword, 12))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
return isValid ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
}
}
This is my authentication class:
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IQueryExecutor queryExecutor;
private readonly IPasswordHasher<User> passwordHasher;
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock,
IQueryExecutor queryExecutor, IPasswordHasher<User> passwordHasher)
: base(options, logger, encoder, clock)
{
this.queryExecutor = queryExecutor;
this.passwordHasher = passwordHasher;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var endpoint = Context.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
return AuthenticateResult.NoResult();
}
if (!Request.Headers.ContainsKey("Authorization"))
{
return AuthenticateResult.Fail("Missing Authorization Header");
}
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);
var query = new GetUserQuery()
{
UserName = username
};
user = await this.queryExecutor.Execute(query);
if (user == null || passwordHasher.VerifyHashedPassword(user, user.PasswordHash, providedPassword)
== PasswordVerificationResult.Failed)
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, user.Role.ToString()),
new Claim(ClaimTypes.Email, user.Email),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
And in this place I am creating a new User:
using MediatR;
using Microsoft.AspNetCore.Identity;
using System.Threading;
using System.Threading.Tasks;
public class AddUserHandler : IRequestHandler<AddUserRequest,
AddUserResponse>
{
private readonly ICommandExecutor commandExecutor;
private readonly IQueryExecutor queryExecutor;
private readonly IMapper mapper;
private readonly IPasswordHasher<User> passwordHasher;
public AddUserHandler(ICommandExecutor commandExecutor,
IQueryExecutor queryExecutor,
IMapper mapper, IPasswordHasher<User> passwordHasher)
{
this.commandExecutor = commandExecutor;
this.queryExecutor = queryExecutor;
this.mapper = mapper;
this.passwordHasher = passwordHasher;
}
public async Task<AddUserResponse> Handle(AddUserRequest
request, CancellationToken cancellationToken)
{
var query = new GetUserQuery()
{
UserName = request.UserName,
Email = request.Email
};
var getUser = await this.queryExecutor.Execute(query);
if (getUser != null)
{
if (getUser.UserName == request.UserName)
{
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.ValidationError +
"! The name is already taken.")
};
}
if (getUser.Email == request.Email)
{
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.ValidationError +
"! Email address is in use.")
};
}
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.Conflict)
};
}
request.PasswordHash = passwordHasher.HashPassword(getUser,
request.Password);
var user = this.mapper.Map<User>(request);
var command = new AddUserCommand()
{
Parameter = user
};
var addedUser = await this.commandExecutor.Execute(command);
var response = new AddUserResponse()
{
Data =
this.mapper.Map<Domain.Models.UserDTO>(addedUser)
};
return response;
}
}
This is my Startup.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions,
BasicAuthenticationHandler>("BasicAuthentication", null);
services.AddScoped<IPasswordHasher<User>,
BCryptPasswordHasher<User>>();
}
Maybe first of all, is it all correct implemented?
Is hash in AddUserHandler correct assigned to request.PasswordHash?
How to retrieve salt and assign to request.PasswordSalt?
Sorry for any unclear things if they occur.
Any feedback and help will be appreciated.
Thanks in advance :)
Edit:
for example if I add user with password "pass123" and it is stored in database as 'user.PasswordHash = "$2a$12$Iqpy7FyQh/pt2O8upTtG5eOQKzo1V395wRNdAXPpp5Qf.NQ.KxUyy"' and provided password after hashing is 'providedPassword = "$2a$12$9vSz8Sw/WtmqGY6jyDiTleN/btZ0wXJkXdoB3sDpANVIIDGBpaqT."'
I fixed the bug if anyone needs to use it in thee future.
The problem was in my authentication class.
In place of:
var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);
Should be:
var username = credentials[0];
var providedPassword = credentials[1];
I am sure that I have checked it a few times but somehow didn't work then. Anyway, it finally works properly.

converting a asp.net mvc to a razor page

I have a asp.net web app that calls a controller action with the following code:
$(function () {
$("#barcode").on("change", function (e) {
// get the current value
var barcode = $('#barcode').val();
// if there's no text, ignore the event
if (!barcode) {
return;
}
// clear the textbox
$("#barcode").val("");
// var holdit = $('#textArea1').val();
$('#textArea1').val($('#textArea1').val() +' '+ barcode);
// post the data using AJAX
$.post('#Url.Action("scanned", "receiveScan")?barcode=' + barcode);
});
})
Controller:
[Produces("application/json")]
[Route("api/receiveScan")]
public class receiveScanController : Controller
{
private static readonly HttpClient client = new HttpClient();
public ActionResult scanned(string barcode)
{
var test = barcode;
receiveScanModel newScan = new receiveScanModel();
newScan.Barcode = barcode;
newScan.companyNo = 1;
string jsonScan = JsonConvert.SerializeObject(newScan, Formatting.Indented);
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://notarealservicehere.azurewebsites.net//api/receivescan");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(jsonScan);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
return Ok();
Trying to convert to my first Razor page, everything works with the exception (obviously) of the $.post part...
Where would this go?
It is a asp.net core app with razor pages
Use a handler for example
on your cs file
public IActionResult OnPostBarcode(string barcode)
on your js
var uri = "myPage/?handler=Barcode"
$.post( uri ,{barcode:barcode}, function( data ) {
console.log(data)
});

How to use #Html.Action instead of ViewComponent in ASP.NET Core

Is there any way to implement #Html.Action method in ASP.NET Core (like it was in ASP.NET MVC)? I know about the ViewComponent feature of ASP.NET Core. But there is a scenario when we have to use Action method.
This is the way to implement this as a HtmlHelper extension.
You can use it as follows:
The last parameter is an anonymous type.
#Html.Action("Action");
#Html.Action("Action", new { string a = "a", int i = 5 }
#Html.Action("Action", "Controller");
#Html.Action("Action", "Controller", new (string a = "a", int i = 5 }
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Mvc.Rendering
{
public static class HtmlHelperViewExtensions
{
public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
{
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
return Action(helper, action, controller, parameters);
}
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
{
var area = (string)helper.ViewContext.RouteData.Values["area"];
return Action(helper, action, controller, area, parameters);
}
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
if (action == null)
throw new ArgumentNullException(nameof(controller));
if (controller == null)
throw new ArgumentNullException(nameof(action));
var task = ActionAsync(helper, action, controller, area, parameters);
return task.Result;
}
private static async Task<IHtmlContent> ActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
// fetching required services for invocation
var currentHttpContext = helper.ViewContext.HttpContext;
var httpContextFactory = GetServiceOrFail<IHttpContextFactory>(currentHttpContext);
var actionInvokerFactory = GetServiceOrFail<IActionInvokerFactory>(currentHttpContext);
var actionSelector = GetServiceOrFail<IActionDescriptorCollectionProvider>(currentHttpContext);
// creating new action invocation context
var routeData = new RouteData();
var routeParams = new RouteValueDictionary(parameters ?? new { });
var routeValues = new RouteValueDictionary(new { area, controller, action });
var newHttpContext = httpContextFactory.Create(currentHttpContext.Features);
newHttpContext.Response.Body = new MemoryStream();
foreach (var router in helper.ViewContext.RouteData.Routers)
routeData.PushState(router, null, null);
routeData.PushState(null, routeValues, null);
routeData.PushState(null, routeParams, null);
var actionDescriptor = actionSelector.ActionDescriptors.Items.First(i => i.RouteValues["Controller"] == controller && i.RouteValues["Action"] == action);
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
// invoke action and retreive the response body
var invoker = actionInvokerFactory.CreateInvoker(actionContext);
string content = null;
await invoker.InvokeAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
content = task.Exception.Message;
}
else if (task.IsCompleted)
{
newHttpContext.Response.Body.Position = 0;
using (var reader = new StreamReader(newHttpContext.Response.Body))
content = reader.ReadToEnd();
}
});
return new HtmlString(content);
}
private static TService GetServiceOrFail<TService>(HttpContext httpContext)
{
if (httpContext == null)
throw new ArgumentNullException(nameof(httpContext));
var service = httpContext.RequestServices.GetService(typeof(TService));
if (service == null)
throw new InvalidOperationException($"Could not locate service: {nameof(TService)}");
return (TService)service;
}
}
}
While it does work and renders the content correctly, when you try to access the IHttpContextAccessor.HttpContext property afterwards it is empty for some reason. I.e. you are opening another controller method which has a reference to IHttpContextAccessor via dependency injection and try to access the HttpContext property after you have renderend an Html.Action-element inside a partial view for example. If I remove the Html.Action-Element, HttpContext is filled correctly. I assume it somehow destroys the context.

Accessing the returned XML from an API call

I have the following action method to perform an API call:-
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Rack rack, FormCollection formValues)
{
if (ModelState.IsValid) {
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (string key in formValues)
{
query[key] = this.Request.Form[key];
}
query["username"] = "testuser";
query["password"] = ///.....
query["assetType"] = "Rack";
query["operation"] = "AddAsset";
var url = new UriBuilder("http://win-spdev:8400/servlets/AssetServlet");
url.Query = query.ToString();
try
{
string xml = client.DownloadString(url.ToString());
}
The return XML from the API call looks as follow:-
<operation>
<operationstatus>Failure</operationstatus>
<message>Rack already exists.Unable to add</message>
</operation>
but how i can reach the message and operationstaus and according to them to display an appropriate message . i use to serialize the returned Json such as , but i am not sure how to do so for the xML:-
var serializer = new JavaScriptSerializer();
var myObject = serializer.Deserialize<newprocess>(json);
string activityid = myObject.activityId;
Just load it into an XmlDocument.
Untested and from the top of my head:
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(theXML);
var status = xmlDoc.SelectSingleNode("/operation/operationstatus").InnerText;
var message = xmlDoc.SelectSingleNode("/operation/message").InnerText;
If you using ASP.NET mvc, I believe you can use HttpClient, instead of WebClient:
Define result class:
public class operation
{
public string operationstatus{get;set;}
public string message{get;set;}
}
And then use it for automatic deserilization:
var client = new HttpClient();
var result = client.PostAsync(url,
new FormUrlEncodedContent(new Dictionary<string, string>{
{"username","testuser"},
{"assetType","Rack"}}))
.Result.Content
.ReadAsAsync<operation>().Result;

WCF Forms Authentication authorization using ASP.NET roles = Access Denied?

I have a basic WPF application where the client writes to a database. I'm using IIS on a server 2012 machine to host the web service. I'm trying to implement Forms authentication, and I have all that working (passing a username and password in the xaml.cs from the client which authenticates my ASP.NET user which works. I then want to implement ASP.NET roles authorization for different commands (Submit Request, Remove Request, etc). The method we're supposed to use is "[PrincipalPermission(SecurityAction.Demand, Role = "Allowed")]"
In theory this should just use the credentials passed in the client (which I've confirmed works) when I try to hit the buttons and it should check if the user I passed is in the role, and if so it allows and if not it denies. However, whether or not the user is in the role it still says "Access is Denied".
Any thoughts?
using System;
using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.Security.Permissions;
using RequestRepository;
using System.Threading;
using System.Web;
namespace RequestServiceLibrary
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class RequestService : IRequestService
{
private List<Request> requests = new List<Request>();
private RequestLibraryEntities context = new RequestLibraryEntities();
[PrincipalPermission(SecurityAction.Demand, Role = "Allowed")]
public string SubmitRequest(Request req)
{
Thread.CurrentPrincipal = HttpContext.Current.User;
if (context.Requests.Count() == 0)
populateRequests();
req.Id = Guid.NewGuid().ToString();
req.TimeSubmitted = DateTime.Now;
requests.Add(req);
addRequest(req);
return req.Id;
}
[PrincipalPermission(SecurityAction.Demand, Role = "Allowed")]
public bool UpdateRequest(Request req)
{
Thread.CurrentPrincipal = HttpContext.Current.User;
bool returnval = false;
try
{
var getobject = requests.Find(x => x.Id.Equals(req.Id));
if (getobject != null) //checks to make sure the object isn't empty
{
getobject.Username = req.Username;
getobject.Password = req.Password;
getobject.RequestedResource = req.RequestedResource;
getobject.TimeSubmitted = req.TimeSubmitted;
}
//Find the request object in the database
var Id = Guid.Parse(req.Id);
var rl = context.Requests.Find(Id);
//Update that object with the values from req
rl.Username = req.Username;
rl.Password = req.Password;
rl.RequestedResource = req.RequestedResource;
rl.TimeTransmitted = req.TimeSubmitted;
context.SaveChanges();
returnval = true;
return returnval;
}
catch (Exception) { return returnval; }
}
public List<Request> GetRequests()
{
populateRequests();
return requests;
}
[PrincipalPermission(SecurityAction.Demand, Role = "Disallowed")]
public bool RemoveRequest(string id)
{
bool rval = false;
try
{
Request req = requests.Find(x => x.Id.Equals(id));
requests.Remove(req);
rval = delRequest(req);
return rval;
}
catch (Exception)
{
return false;
}
}
private void populateRequests()
{
requests = new List<Request>();
var rl = context.Requests.ToList();
foreach (var r in rl)
{
requests.Add(new Request()
{
Id = r.Id.ToString(),
Password = r.Password,
RequestedResource = r.RequestedResource,
TimeSubmitted = r.TimeTransmitted,
Username = r.Username
});
}
}
private void addRequest(Request req)
{
try
{
var r = context.Requests.Create();
r.Id = Guid.Parse(req.Id);
r.Username = req.Username;
r.Password = req.Password;
r.RequestedResource = req.RequestedResource;
r.TimeTransmitted = req.TimeSubmitted;
context.Requests.Add(r);
context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Console.WriteLine("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
private bool delRequest(Request req)
{
Guid Id = Guid.Parse(req.Id);
var r = context.Requests.Create();
r.Id = Id;
var rl = context.Requests.Find(Id);
try
{
context.Requests.Remove(rl);
context.SaveChanges();
return true;
}
catch (Exception) { return false; }
}
}
}
In order to be able to use PrincipalPermissionAttribute in this way, you need to first set Thread.CurrentPrincipal to a Principal with the appropriate roles ("Allowed" in this case).
For example you could use ClientRoleProvider to do this, or simply create the Principal manually (possibly using roles you retrieve from the web service).

Resources