Blazor: How can i check if the Param for the Callback function does exsist? - blazor-server-side

Example:
/Parent
<SomeTemplate event="#ThisEvent"/>
#code{
private async Task ThisEvent()
{
}
/Child
#Code {
[Parameter]
public EventCallback event{ get; set; }
}
Is there a way to "check" if "event" has been passed to the Child as parameter ?
I want to use this in the Child to decide "what" this implementation of this Template should show and what not
The only Solution i have is to pass additional bool values to do so, im looking for a away to avoid that

Here's how to check if a delegate has been assigned to the callback. I've set up the check to throw a Debug break if nothing has been assigned.
Also note the EditorRequired setting on the parameter which will produce a warning in the editor if that's what you want.
#using System.Diagnostics;
<h3>CallbackComponent</h3>
#code {
[Parameter, EditorRequired] public EventCallback<int> MyEventCallback { get; set; }
protected override void OnInitialized()
{
Debug.Assert(this.MyEventCallback.HasDelegate);
}
private async Task OnClick(MouseEventArgs e)
{
await this.MyEventCallback.InvokeAsync(1);
}
}

Checking for whether a delegate has been assigned is what you are after:
public EventCallback MyEventCallback { get; set; }
public async Task MyHandler()
{
if (MyEventCallback.HasDelegate)
{
await MyEventCallback.InvokeAsync();
}
}

Related

Is it possible to use "PropertyChanged" on a bool in .NET MAUI?

I have been trying to detect it when these variables change, but I don't know how to do that since bools aren't supported by the "PropertyChanged" function.
I also tried using the communityToolKit, but I have no idea how to use that.
I want it to call the function "IconUpdater"
public class Status : INotifyPropertyChanged
{
public static bool isWorking { get; set; } = Preferences.Get("IsWorking", true);
public static bool isPaused { get; set; } = Preferences.Get("IsPaused", false);
public static void IconUpdater()
{
// The function I want to call \\
}
public event PropertyChangedEventHandler PropertyChanged;
}
You can use PropertyChanged event to notify the changes of IsEnabled property in your viewmodel.
Here's the code snippet below for your reference:
public class MainPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _isWorking;
public bool IsEnabled
{
get
{
return _isWorking;
}
set
{
if(_isWorking != value)
{
_isWorking = value;
var args = new PropertyChangedEventArgs(nameof(IsEnabled));
PropertyChanged?.Invoke(this, args);
}
}
}
}
I recommend using the Community Toolkit MVVM package: https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/
You can then simply do the following to use the INotifyPropertyChanged interface:
using CommunityToolkit.Mvvm;
public class MyViewModel : ObservableObject
{
private bool _myBool;
public bool MyBool
{
get => _myBool;
set => SetProperty(ref _myBool, value);
}
}
You can also modify the code in such a way that you directly call any other method from within the setter:
private bool _myBool;
public bool MyBool
{
get => _myBool;
set
{
SetProperty(ref _myBool, value);
IconUpdater();
}
}
Please mind that your class is using static properties. You cannot use INotifyPropertyChanged for that.

Action filter does not override controller action?

I have implemented an IAsyncAuthorizationFilter/IActionFilter filter and implemented TypeFilterAttribute for the filter. When I add the attribute to both the controller and action, the action filter does not appear to override the controller level filter.
public class MyAuthorizeAttribute : TypeFilterAttribute
{
public MyAuthorizeAttribute (bool redirectOnFailure = true)
: base(typeof(MyFilter))
{
Arguments = new object[]
{
redirectOnFailure
};
}
}
public class MyFilter: IAsyncAuthorizationFilter, IActionFilter
{
public bool RedirectOnFailure { get; set; }
public MyFilter(bool redirectOnFailure)
{
RedirectOnFailure = redirectOnFailure;
}
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.Controller is Controller controller)
{
// Do some work
if (true)
{
if (!RedirectOnFailure)
{
context.Result = new JsonResult("Your session has expired.");
}
else
{
context.Result = new RedirectResult("LoginUrl");
}
return;
}
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do nothing
}
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
// Do work
}
}
The redirectOnFailure will be true for the Index action even though the filter specified false. In ASP.NET MVC, the action filter would override the controller filter. You could have a default for all actions but override specific actions with different properties/parameters. Can you not do this in Core?
[MyAuthorize]
public class HomeController : Controller
{
[MyAuthorize(redirectOnFailure: false)]
public IActionResult Index()
{
// Do work
}
}
As per the Microsoft website, filters do not override each other. They simply run one after the other in the order described in the cited document.
Just because the same attribute is put in both the controller and the action doesn't mean that ASP.net will say "ah, you probably want to override the class-level attribute". That's just not how it works.
If you want override logic, you need to write override logic.
Here's a sample made for .Net 6. The magic is done by the FindEffectivePolicy() method. This sample shows how to compare the current object against the effective one and only run the logic if the comparison matches.
public class MyFilter : IAsyncAuthorizationFilter
{
#region Properties
public string Name { get; }
#endregion
#region Constructors
public MyFilter(string name)
{
Name = name;
}
#endregion
#region IAsyncAuthorizationFilter
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var effectiveAtt = context.FindEffectivePolicy<MyFilter>();
System.Diagnostics.Debug.Print($"Effective filter's name: {effectiveAtt?.Name}");
System.Diagnostics.Debug.Print($"Am I the effective attribute? {this == effectiveAtt}");
if (this == effectiveAtt)
{
// Do stuff since this is the effective attribute (policy).
}
else
{
// ELSE part probably not needed. We just want the IF to make sure the code runs only once.
}
return Task.CompletedTask;
}
#endregion
}

AuthenticationState always returns null after successful log in

So i have this set up in another project, but when i have come to use exactly the same method, it always returns null
#code {
[CascadingParameter]
private Task<Microsoft.AspNetCore.Components.Authorization.AuthenticationState> authState { get; set; }
private System.Security.Claims.ClaimsPrincipal principal;
public string displayName { get; set; }
private bool collapseNavMenu = true;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
protected async override void OnParametersSet()
{
principal = (await authState).User;
displayName = principal.Claims.FirstOrDefault(c => c.Type == "display_name").Value;
}
}
I can't figure out why this is the case, the startup class configure and configure services are pretty much identical. Can anyone point me in the direction on why this maybe the case?
Thanks
I ran into AuthenticationState being null in a Blazor Service App. Check that <CascadingAuthenticationState>
is wrapped around the contents of the App.razor file.
See https://learn.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-5.0

Application Menu with Security Trimming

I came from asp.net 2.0 webforms; where i just define my menu in Web.sitemap with all the trimming taken care off.
Is there any equivalent feature in asp.net-core-mvc for this seemingly easy task ?
You can create a custom TagHelper for it, inside this tag helper you can check whether user is in apporperiate role or not:
public class SecurityTrimmingTagHelper : TagHelper
{
[ViewContext]
public ViewContext Context { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;
if (!Context.HttpContext.User.Identity.IsAuthenticated)
{
output.SuppressOutput();
}
if (Context.HttpContext.User.IsInRole("Admin"))
{
return;
}
output.SuppressOutput();
}
}

Use session state for an ApiController

I want to have my own AppContext in my ApiController (MVC4).
Should be something like
public class TestController : BaseApiController
{
[HttpGet]
public IEnumerable<TestVM> GetAll()
{
// the test service is injected with SimpleInjector
return _testService.GetAll(**base.AppContext**);
}
}
but the ApiController haven't access to the Session.
Are there any solutions to "activate" the Session for specific keys (because I don't want the whole Session)?
Or do you have any other idea (cache or cookie)?
This is the BaseApiController
public abstract class BaseApiController: ApiController
{
public IAppContext AppContext
{
get { return SessionState.AppContext; }
}
}
and this is my IAppContext (it will have more properties in the future)
public interface IAppContext
{
IIdentity User { get; }
/// <summary> Gets the user id. </summary>
/// <value>The user id.</value>
int IdUser { get; }
}
here the application module which is registered in the web.config
public class ApplicationModule : IHttpModule
{
// ...
SessionState.AppContext = _appContext.InitializeNew(
HttpRuntime.AppDomainAppPath, languages);
// ...
}
SessionState class to get the AppContext
public class SessionState : BaseSessionVariables
{
public static IAppContext AppContext
{
get { return SessionState.Get<IAppContext>("AppContext"); }
set { SessionState.Set("AppContext", value); }
}
}
here the BaseSessionVariables class
public static HttpSessionState GetSession()
{
return HttpContext.Current.Session;
}
protected static T Get<T>(string key) where T : class
{
var session = BaseSessionVariables.GetSession();
if (session == null)
{
throw new Exception("No session");
}
return (session[key] as T);
}
Thanks for your help!
Take a look at the implementation below. It should get you headed in the right direction.
Updated IAppContext - Added Setters
public interface IAppContext
{
IIdentity User { get; set; }
/// <summary> Gets the user id. </summary>
/// <value>The user id.</value>
int IdUser { get; set; }
}
Updated Base Controller - Instantiates a new AppContextImplemenation in the OnActionExecuting method
public abstract class BaseApiController: ApiController
{
public IAppContext AppContext {get; set;}
protected override void OnActionExecuting(
ActionExecutingContext filterContext)
{
AppContext = new AppContextImplementation();
}
}
New Class - implements IAppContext and wraps the HttpContext Session. For testing you can then create an TestAppContextImplementation that doesn't rely on Session but some other in memory storage mechanism.
public class AppContextImplementation : IAppContext
{
public IIdentity User
{
get { return HttpContext.Current.Session["User"] as IIdentity; }
set { HttpContext.Current.Session["User"] = value; }
}
int IdUser
{
get { return Convert.ToInt32(Session["IdUser"]); }
set { Session["IdUser"] = value; }
}
}
For ApiControllers, build yourself a DelegatingHandler and push all of your goodies onto request.Properties. You can then retrieve them from your request whether you are testing or running live. The benefit is that you then have zero dependency on Session in your Controller.
MessageHandler
public class ContextHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
// get the goodies to add onto the request
var goodies = /* call to goodieGoodieYumYum */
// add our goodies onto the request
request.Properties.Add(Constants.RequestKey_Goodies, goodies);
// pass along to the next handler
return base.SendAsync(request, cancellationToken);
}
}
Controller Action
var goodies = (List<Goodie>)Request.Properties[Constants.RequestKey_Goodies];