Can I use the dynamic feature of Profile inside a MVC Controller? - c#

I suspect this only applies to asp.net pages, but according to this:
http://msdn.microsoft.com/en-us/library/2y3fs9xs.aspx
I can define properties in web.config like so:
<profile>
<properties>
<add name="PostalCode" />
</properties>
</profile>
Then go ahead and use them like this:
Profile.PostalCode = txtPostalCode.Text;
But this does not compile for me inside a Controller:
public ActionResult Index()
{
Profile.PostalCode = "codeofpost";
return View();
}
Profile is of type ProfileBase and not dynamic, so I've no idea how this would work, but the document says otherwise.

Profile class is generated only in ASP.NET Website project NOT in ASP.NET Web aplication.
In Web Application project you need to use
ProfielBase.GetPropertyValue(PropertyName);
References: http://weblogs.asp.net/anasghanem/archive/2008/04/12/the-differences-in-profile-between-web-application-projects-wap-and-website.aspx

As I've been told it's not possible, I've decided to use a dynamic to do this for myself. I guess it's just syntactic sugar in the end.
Descending from this enables Profile.PostalCode = "codeofpost";
/// <summary>
/// Provides a dynamic Profile.
/// </summary>
public abstract class ControllerBase : Controller
{
private readonly Lazy<DynamicProfile> _dProfile;
protected ControllerBase()
{
_dProfile = new Lazy<DynamicProfile>(() => new DynamicProfile(base.Profile));
}
private sealed class DynamicProfile : DynamicObject
{
private readonly ProfileBase _profile;
public DynamicProfile(ProfileBase profile)
{
_profile = profile;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = _profile.GetPropertyValue(binder.Name);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_profile.SetPropertyValue(binder.Name, value);
_profile.Save();
return true;
}
}
/// <summary>
/// New dynamic profile, can now access the properties as though they are on the Profile,
/// e.g. Profile.PostCode
/// </summary>
protected new dynamic Profile
{
get { return _dProfile.Value; }
}
/// <summary>
/// Provides access to the original profile object.
/// </summary>
protected ProfileBase ProfileBase
{
get { return base.Profile; }
}
}

Related

OData disable serialization of nullable object

how can i disable serialization of null objects?
In my startup.cs i have:
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull;
})
.AddOData(options =>
{
options.Filter().Select().OrderBy().Count().SetMaxTop(serviceSettings.MaxPageSize).SkipToken().AddRouteComponents("api", GetEdmModel());
});
But still in result json i see "PropName": null
It is possible to use NewtonSoft in Odata?
I found someting like this Microsoft.AspNetCore.OData.NewtonsoftJson but I don't know how can I use it.
You can do it using a custom serializer:
Create a serializer:
public class IngoreNullEntityPropertiesSerializer : ODataResourceSerializer
{
public IngoreNullEntityPropertiesSerializer(ODataSerializerProvider provider)
: base(provider) { }
/// <summary>
/// Only return properties that are not null
/// </summary>
/// <param name="structuralProperty">The EDM structural property being written.</param>
/// <param name="resourceContext">The context for the entity instance being written.</param>
/// <returns>The property be written by the serilizer, a null response will effectively skip this property.</returns>
public override Microsoft.OData.ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, ResourceContext resourceContext)
{
var property = base.CreateStructuralProperty(structuralProperty, resourceContext);
return property.Value != null ? property : null;
}
}
Create a serializer provider:
public class IngoreNullEntityPropertiesSerializerProvider : ODataSerializerProvider
{
private readonly IngoreNullEntityPropertiesSerializer entityTypeSerializer;
public IngoreNullEntityPropertiesSerializerProvider(IServiceProvider rootContainer)
: base(rootContainer)
{
entityTypeSerializer = new IngoreNullEntityPropertiesSerializer(this);
}
public override IODataEdmTypeSerializer GetEdmTypeSerializer(Microsoft.OData.Edm.IEdmTypeReference edmType)
{
if (edmType.Definition.TypeKind == EdmTypeKind.Entity)
return entityTypeSerializer;
else
return base.GetEdmTypeSerializer(edmType);
}
}
Add the provider to services:
services.AddControllers().AddOData(opt => opt.Select().Expand().AddRouteComponents("odata", GetEdmModel(), conf => conf.AddSingleton<IODataSerializerProvider, IngoreNullEntityPropertiesSerializerProvider>()));
Note: I would not recommend you to do that because your response will be as anonymous. It may cause problems when you use it. Also, some of IDE which can integrate with OData will not, work properly. For example when you put data into excel it will show this error:

ASP.NET Core routing - mapping only specific controllers

Per documentation it seems like it's only possible to add either single routes, one by one, or add all routes in annotated (attribute routing) controllers
DOCS: Routing to controller actions in ASP.NET Core
Is it possible to add only all routes belonging to single Controller?
Using UseEndpoints(e => e.MapControllers()) will add all controllers that are annotated, using UseEndpoints(e => e.MapControllerRoute(...)) seems to be able to add only single controller/action route, not all routes that are annotated in given controller
Sample controller:
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[controller]")]
public class MyApiController
{
[Route("/")]
[Route("[action]")]
[HttpGet]
public ResponseType Index()
{
// ...
}
[Route("[action]")]
public ResponseType GetListing()
{
// ...
}
}
One solution I found is to build a custom MVC feature provider and implement an extension method that allows you to specify exactly which controllers you want registered.
public static class MvcExtensions
{
/// <summary>
/// Finds the appropriate controllers
/// </summary>
/// <param name="partManager">The manager for the parts</param>
/// <param name="controllerTypes">The controller types that are allowed. </param>
public static void UseSpecificControllers(this ApplicationPartManager partManager, params Type[] controllerTypes)
{
partManager.FeatureProviders.Add(new InternalControllerFeatureProvider());
partManager.ApplicationParts.Clear();
partManager.ApplicationParts.Add(new SelectedControllersApplicationParts(controllerTypes));
}
/// <summary>
/// Only allow selected controllers
/// </summary>
/// <param name="mvcCoreBuilder">The builder that configures mvc core</param>
/// <param name="controllerTypes">The controller types that are allowed. </param>
public static IMvcCoreBuilder UseSpecificControllers(this IMvcCoreBuilder mvcCoreBuilder, params Type[] controllerTypes) => mvcCoreBuilder.ConfigureApplicationPartManager(partManager => partManager.UseSpecificControllers(controllerTypes));
/// <summary>
/// Only instantiates selected controllers, not all of them. Prevents application scanning for controllers.
/// </summary>
private class SelectedControllersApplicationParts : ApplicationPart, IApplicationPartTypeProvider
{
public SelectedControllersApplicationParts()
{
Name = "Only allow selected controllers";
}
public SelectedControllersApplicationParts(Type[] types)
{
Types = types.Select(x => x.GetTypeInfo()).ToArray();
}
public override string Name { get; }
public IEnumerable<TypeInfo> Types { get; }
}
/// <summary>
/// Ensure that internal controllers are also allowed. The default ControllerFeatureProvider hides internal controllers, but this one allows it.
/// </summary>
private class InternalControllerFeatureProvider : ControllerFeatureProvider
{
private const string ControllerTypeNameSuffix = "Controller";
/// <summary>
/// Determines if a given <paramref name="typeInfo"/> is a controller. The default ControllerFeatureProvider hides internal controllers, but this one allows it.
/// </summary>
/// <param name="typeInfo">The <see cref="TypeInfo"/> candidate.</param>
/// <returns><code>true</code> if the type is a controller; otherwise <code>false</code>.</returns>
protected override bool IsController(TypeInfo typeInfo)
{
if (!typeInfo.IsClass)
{
return false;
}
if (typeInfo.IsAbstract)
{
return false;
}
if (typeInfo.ContainsGenericParameters)
{
return false;
}
if (typeInfo.IsDefined(typeof(Microsoft.AspNetCore.Mvc.NonControllerAttribute)))
{
return false;
}
if (!typeInfo.Name.EndsWith(ControllerTypeNameSuffix, StringComparison.OrdinalIgnoreCase) &&
!typeInfo.IsDefined(typeof(Microsoft.AspNetCore.Mvc.ControllerAttribute)))
{
return false;
}
return true;
}
}
}
Put the extensions class wherever in your project, and use like this
public void ConfigureServices(IServiceCollection services)
{
// put this line before services.AddControllers()
services.AddMvcCore().UseSpecificControllers(typeof(MyApiController), typeof(MyOtherController));
}
Source: https://gist.github.com/damianh/5d69be0e3004024f03b6cc876d7b0bd3
Courtesy of Damian Hickey.

How do I resolve HttpContext from a RegisterEvent to retrieve a View in a string in asp.net core 3and Electron.net?

I've tried Dependency injection, but that always gives me a HttpContextAccessor.Current or ActionContext as null because I'm not in a request state (I think). So how can I get this context to just take a view, transform it to a html string (with Model if necessary) and throw it back in JS ? I even tried to call directly the Controller action, but it always gives HttpContext as null... I'm using Asp.NET Core 3.
Please, if someone has been going through, help me :-)
Thanks,
Edit:
I have an asp.net core based on Electron.net for a desktop application. I use a lot of IPC communication to retrieve data from backend c# using Electron.IpcMain.On. I register an action as listener in c# in a class. The main problem is that this class is really outside a normal HttpRequest or a Controller. Here is some sample code:
IpcBase Class
public abstract class IpcBase: IBaseIpcCommunicationClass
{
/// <summary>
/// Find a way to get rid of this and take more than the first window
/// </summary>
protected static BrowserWindow _mainWindow = Electron.WindowManager.BrowserWindows.First();
/// <summary>
/// Send an ipcEvent with a parameter class
/// </summary>
/// <param name="parameters">Parameters to fill</param>
public void RegisterIpcEvent<T>(IpcRegisterModel<T> registerModel) => Electron.IpcMain.On(registerModel.key, o => registerModel.action((T)
((JObject)o).ToObject(typeof(T))));
/// <summary>
/// Send a reply inside a registerevent
/// </summary>
/// <typeparam name="T">Type of model</typeparam>
/// <param name="model">model</param>
public void SendReply<T>(IpcSendParamsModel<T> model)
{
if (!string.IsNullOrEmpty(model.replyTo))
{
Electron.IpcMain.Send(_mainWindow, model.replyTo, model);
}
}
...
}
IpcUI (to get the controller view, just like an ajax call on a controller that retrieve the view in String (I already have that, but not with Ipc)
public class IpcUI: IpcBase
{
public IpcUI(IRazorViewToStringService razorViewRenderService)
{
Console.WriteLine("IpcUI::Constructor");
RegisterIpcEvent(new IpcRegisterModel<IpcSendParamsModel<AjaxPartialModel>>("renderPartial", async (param) =>
{
var param = new IpcSendParamsModel<AjaxPartialModel>("RenderPartial")
{
key = "renderPartial",
model = new AjaxPartialModel()
{
DataModel = "{items: [{\r\n MaterialIcon: \"\",\r\n Title: \"Games\",\r\n Selectable: true,\r\n Active: true,\r\n Key: \"GAMES\",\r\n BadgeCaption: \"new\",\r\n BadgeValue: \"123\",\r\n BadgeColor: \"red darken-1\",\r\n BadgePartialLink: \"\",\r\n BadgeContainerLink: \"\",\r\n BadgeModelLink: \"\",\r\n PartialLink: \"Home/Index\",\r\n ContainerLink: \"#body-content\",\r\n ModelLink: \"\"\r\n }] }".JsonDeserialize<MenuModelHeader>(),
PartialName = "PartialViews/_TopMenu"
}
};
try
{
param.results =
await razorViewRenderService.CreateAndResolveInstanceFromGeneric().RenderViewToStringAsync($"~/Views/{param.model.PartialName}.cshtml",
param.model.DataModel);
}
catch (Exception e)
{
IpcClasses.ExceptionManager.SendException(this, e, $"IpcUI params: {param.model.JsonSerialize()}");
}
}));
}
}
Razor Service (Mostly taken from here Generate string from view)
Added in startup:
services.AddHttpContextAccessor();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IRazorViewToStringService, RazorRazorViewToStringService>();
When I create an instance of IpcUI, DI gives me the service, but without any HttpContext or ActionContext... Sorry for the lack of information from my last edit :-). Hope it is a bit more specific.
Oh ! I forgot something, IpcUI is created at runtime not with a new (because that don't work) but with a custom extension function that retrieves the IServiceProvider for DI:
In startup
ExtensionsUtils.ServiceProvider = app.ApplicationServices;
In ExtensionsUtils
/// <summary>
/// This is called in configure services to get the collection of services in an extension static class
/// </summary>
public static IServiceProvider ServiceProvider { get; set; }
/// <summary>
/// Create a reference from type T with DI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="o"></param>
/// <returns></returns>
public static T CreateAndResolveInstanceFromGeneric<T>(this T o)
{
return (T)ActivatorUtilities.CreateInstance<T>(ServiceProvider);
}
Edit 2:
I have tried to access IRazorViewToStringService from a real controller constructor and it's null again... What Am I doing wrong ???
private readonly IRazorViewToStringService _razorViewRenderService;
public BaseController(IRazorViewToStringService razorViewRenderService)
{
_razorViewRenderService = razorViewRenderService;
}
...
/// <summary>
/// Return a success http code and a View rendered as string
/// </summary>
/// <param name="ViewName">Name of MVC View (or PartialView)</param>
/// <param name="Model">Model to pass if any</param>
/// <returns>JSON: { result: "type", description: "Html Code" }</returns>
public async Task<ActionResult> CheckAndReturnView(string ViewName, object Model = null)
{
return Ok(await _razorViewRenderService.RenderViewToStringAsync(ViewName, Model));
}

How to access Extension method from view context in MVC Core 2

I want access ViewContext on view because I have created extension method and using that extension I want to access Base Controller on View.
Refer to the code below
public static class ViewContextExtension
{
public static BaseController BaseController(this ControllerContext view)
{
BaseController objBaseController = null;
if (view != null)
objBaseController = view.Controller as BaseController;
return objBaseController;
}
}
I want to use same code in MVC Core 2 but I am not able access it on view side.
Previously I was using it in MVC 5.2.3 E.g.
!ViewContext.BaseController().IsMobileDevice
I have found solution for above question. refer below.
Use Name library.
using Microsoft.AspNetCore.Mvc;
Find code below
public static class ControllerContextExtension
{
/// <summary>
/// BaseController
/// </summary>
/// <param name="view"></param>
/// <returns></returns>
public static BaseController BaseController(this ControllerContext view)
{
var factory = CreateControllerFactory();
return factory.CreateController(view) as BaseController;
}
private static DefaultControllerFactory CreateControllerFactory()
{
var propertyActivators = new IControllerPropertyActivator[]
{
new DefaultControllerPropertyActivator(),
};
return new DefaultControllerFactory(
new DefaultControllerActivator(new TypeActivatorCache()),
propertyActivators);
}
}
Access above code in view as below .cshtml.
controllerContext.BaseController().IsMobileDevice
Suggest if we can improve above code. Happy coding.

Interfaces for mocking ConfirmEmailAsync and other UserManager methods in MVC5

I am trying to unit test this controller method, which comes out of the box in current MVC projects.
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return View("Error");
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
The AccountController has a constructor which will take an ApplicationUserManager and a ApplicationSignInManager as parameters, and the matching properties with private setters to use for testing. However, I can't figure out how to mock out the ConfirmEmailAsync method.
You can mock various interfaces in the Identity namespace:
var store = new Mock<IUserStore<ApplicationUser>>();
store.As<IUserEmailStore<ApplicationUser>>()
.Setup(x => x.FindByIdAsync("username1"))
.ReturnsAsync((ApplicationUser)null);
var mockManager = new ApplicationUserManager(store.Object);
AccountController ac = new AccountController(mockManager, null, GetMockRepository().Object, GetMockLogger().Object);
But I can't find or figure out which Interface I need in order to create a mock of ConfirmEmailAsync.
How do I go about this? And for reference, is there a good way of finding out which interfaces these methods are on in order to mock and test them?
ConfirmEmailAsync is not currently part of an interface in the framework. It's in the UserManager<TUser, TKey> class which is the base class of Identity framework.
My solution?
Abstract all the things
I got around this by abstracting most of the functionality of identity into its own project so that I can unit test it easier and reuse the abstraction in other projects. I got the idea after reading this article
Persistence-Ignorant ASP.NET Identity with Patterns
I then fine tuned the idea to suit my needs. I basically just swapped everything i needed from asp.net.identity for my custom interfaces which more or less mirrored the functionality provided by the framework but with the advantage of easier mockability.
IIdentityUser
/// <summary>
/// Minimal interface for a user with an id of type <seealso cref="System.String"/>
/// </summary>
public interface IIdentityUser : IIdentityUser<string> { }
/// <summary>
/// Minimal interface for a user
/// </summary>
public interface IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
TKey Id { get; set; }
string UserName { get; set; }
string Email { get; set; }
bool EmailConfirmed { get; set; }
string EmailConfirmationToken { get; set; }
string ResetPasswordToken { get; set; }
string PasswordHash { get; set; }
}
IIdentityManager
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager : IIdentityManager<IIdentityUser> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser> : IIdentityManager<TUser, string>
where TUser : class, IIdentityUser<string> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser, TKey> : IDisposable
where TUser : class, IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
Task<IIdentityResult> AddPasswordAsync(TKey userid, string password);
Task<IIdentityResult> ChangePasswordAsync(TKey userid, string currentPassword, string newPassword);
Task<IIdentityResult> ConfirmEmailAsync(TKey userId, string token);
//...other code removed for brevity
}
IIdentityResult
/// <summary>
/// Represents the minimal result of an identity operation
/// </summary>
public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> {
bool Succeeded { get; }
}
In my default implementation of the identity manager i simply wrapped the ApplicationManager and then mapped results and functionality between my types and the asp.net.identity types.
public class DefaultUserManager : IIdentityManager {
private ApplicationUserManager innerManager;
public DefaultUserManager() {
this.innerManager = ApplicationUserManager.Instance;
}
//..other code removed for brevity
public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) {
var result = await innerManager.ConfirmEmailAsync(userId, token);
return result.AsIIdentityResult();
}
//...other code removed for brevity
}
Disclaimer: I work at Typemock.
Actually you don't need any interface if you are using Typemock, you just need to fake the IdentityResult you require and change the behavior of the asynchronous method "ConfirmEmailAsync", for example a test that checks the scenario of an Unconfirmed email:
[TestMethod, Isolated]
public async Task TestWhenEmailIsBad_ErrorMessageIsShown()
{
// Arrange
// Create the wanted controller for testing and fake IdentityResult
var controller = new aspdotNetExample.Controllers.AccountController();
var fakeIdentityRes = Isolate.Fake.Instance<IdentityResult>();
// Fake HttpContext to return a fake ApplicationSignInManager
var fakeSIM = Isolate.WhenCalled(() => controller.UserManager).ReturnRecursiveFake();
// Modifying the behavior of ConfirmEmailAsync to return fakeIdentityRes
Isolate.WhenCalled(() => fakeSIM.ConfirmEmailAsync("", "")).WillReturn(Task.FromResult<IdentityResult>(fakeIdentityRes));
Isolate.WhenCalled(() => fakeIdentityRes.Succeeded).WillReturn(false);
// Act
var result = await controller.ConfirmEmail("", "") as ViewResult;
// Assert
Assert.AreEqual("Error", result.ViewName);
}

Categories