Hello, sorry for the late reply.
I will create an internal issue on the subject.
I can suggest the following code as a workaround. It's not a workaround that will meet all your needs, but it still works:
1-) Create menu.js
in wwwroot
folder as follow:
$(function () {
// Function to toggle the settings menu visibility
function toggleSettingsMenu() {
const settingsMenu = document.querySelector('[data-lpx-context-menu="settings-context-menu"]');
settingsMenu.classList.toggle('show');
}
// Function to handle keyboard events on the settings menu item
function handleSettingsMenuItemKeydown(event) {
if (event.key === 'Enter') {
event.preventDefault(); // Prevent default action for "Enter" key
toggleSettingsMenu(); // Toggle the settings menu visibility
}
}
// Function to add keyboard accessibility to the settings menu
function addKeyboardAccessibilityToSettingsMenu() {
const settingsMenuItem = document.getElementById('lpx-settings');
settingsMenuItem.setAttribute('tabindex', '0');
settingsMenuItem.addEventListener('keydown', handleSettingsMenuItemKeydown);
settingsMenuItem.addEventListener('blur', () => {
const settingsMenu = document.querySelector('[data-lpx-context-menu="settings-context-menu"]');
settingsMenu.classList.remove('show');
}); // Close the settings menu when focus is lost
const settingIcons = document.querySelectorAll('.setting-icon');
settingIcons.forEach(item => {
item.setAttribute('tabindex', '0');
item.addEventListener('keydown', handleSubMenuItemKeydown);
});
}
addKeyboardAccessibilityToSettingsMenu();
function handleMenuItemKeydown(event) {
if (event.key === 'Enter') {
event.preventDefault(); // Prevent default action for "Enter" key
// Toggle the sub-menu visibility
const subMenu = event.currentTarget.querySelector('.lpx-inner-menu');
if (subMenu) {
subMenu.classList.toggle('show');
if (subMenu.classList.contains('show')) {
const subMenuItems = subMenu.querySelectorAll('.lpx-menu-item-link');
subMenuItems.forEach(item => item.setAttribute('tabindex', '0'));
} else {
const subMenuItems = subMenu.querySelectorAll('.lpx-menu-item-link');
subMenuItems.forEach(item => item.removeAttribute('tabindex'));
}
}
} else if (event.key === 'ArrowDown') {
event.preventDefault(); // Prevent default action for "ArrowDown" key
// Focus on the next menu item
const nextMenuItem = event.currentTarget.nextElementSibling;
if (nextMenuItem) {
nextMenuItem.querySelector('.lpx-menu-item-link').focus();
}
} else if (event.key === 'ArrowUp') {
event.preventDefault(); // Prevent default action for "ArrowUp" key
// Focus on the previous menu item
const prevMenuItem = event.currentTarget.previousElementSibling;
if (prevMenuItem) {
prevMenuItem.querySelector('.lpx-menu-item-link').focus();
}
}
}
// Function to handle keyboard events on sub-menu items
function handleSubMenuItemKeydown(event) {
if (event.key === 'Enter') {
event.preventDefault(); // Prevent default action for "Enter" key
// Perform the desired action for the sub-menu item (you can open sub-menus here)
const linkElement = event.target.closest('.lpx-menu-item-link');
if (linkElement) {
window.location.href = linkElement.getAttribute('href');
}
} else if (event.key === 'ArrowDown') {
event.preventDefault(); // Prevent default action for "ArrowDown" key
// Focus on the next sub-menu item
const nextSubMenuItem = event.currentTarget.nextElementSibling;
if (nextSubMenuItem) {
nextSubMenuItem.querySelector('.lpx-menu-item-link').focus();
}
} else if (event.key === 'ArrowUp') {
event.preventDefault(); // Prevent default action for "ArrowUp" key
// Focus on the previous sub-menu item
const prevSubMenuItem = event.currentTarget.previousElementSibling;
if (prevSubMenuItem) {
prevSubMenuItem.querySelector('.lpx-menu-item-link').focus();
}
}
}
// Function to add keyboard accessibility to the menu
function addKeyboardAccessibilityToMenu() {
const menuItems = document.querySelectorAll('.lpx-menu-item');
menuItems.forEach(item => {
item.setAttribute('tabindex', '0');
item.addEventListener('keydown', handleMenuItemKeydown);
});
const subMenuItems = document.querySelectorAll('.lpx-inner-menu-item');
subMenuItems.forEach(item => {
item.setAttribute('tabindex', '-1');
item.addEventListener('keydown', handleSubMenuItemKeydown);
});
}
// Call the function to enable keyboard accessibility for the menu
addKeyboardAccessibilityToMenu();
});
2-) Configure AbpBundlingOptions
in the module class of your web project as follow:
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
LeptonXThemeBundles.Styles.Global,
bundle =>
{
...
}
);
options.ScriptBundles.Configure(
LeptonXThemeBundles.Styles.Global,
bundle =>
{
...
bundle.AddFiles("/menu.js");
...
});
});
Hello, @enis and I have done a lot of research to be able to recommend you a workaround, but unfortunately, we could not find a suitable workaround. In order not to encounter similar problems in future versions, we have made the relevant parts of LeptonX
overridable. The issue was resolved in version 7.2.*
and with 7.4.*
we will make it possible to override it if desired, but unfortunately, this is not possible in version 6.0.1
.
Sorry for the late reply.
This problem has already been solved in version 7.2.*
. You can upgrade your application.
You are welcome :)
Instead of getting the XSRF-TOKEN
from the cookie, you can get it as follows?
AntiForgeryManager.GenerateToken()
Full code example:
@page "/Upload"
@using Volo.Abp.AspNetCore.Mvc.AntiForgery
@inject NavigationManager NavigationManager
@inject IAbpAntiForgeryManager AntiForgeryManager // added
<div id="overviewDemoDropZone" class="card custom-drop-zone bg-light rounded-3 w-100 m-0">
<span class="drop-file-icon mb-3"></span>
<span>Drag and Drop File Here</span><span class="m-1">or</span>
<button id="overviewDemoSelectButton" class="btn border-primary btn-primary m-1">Select File</button>
</div>
<DxUpload Name="myFile"
Visible="@UploadVisible"
ExternalSelectButtonCssSelector="#overviewDemoSelectButton"
ExternalDropZoneCssSelector="#overviewDemoDropZone"
ExternalDropZoneDragOverCssClass="bg-light border-secondary text-dark"
MaxFileSize="15000000"
UploadUrl="@GetUploadUrl("api/Upload/Upload/")"
SelectedFilesChanged="@SelectedFilesChanged"
FileUploadStart="FileUploadStart"
CssClass="w-100">
</DxUpload>
@code {
bool UploadVisible { get; set; } = false;
protected void SelectedFilesChanged(IEnumerable<UploadFileInfo> files) {
UploadVisible = files.ToList().Count > 0;
InvokeAsync(StateHasChanged);
}
protected string GetUploadUrl(string url) {
return NavigationManager.ToAbsoluteUri(url).AbsoluteUri;
}
protected void FileUploadStart(FileUploadStartEventArgs args) {
args.RequestHeaders.Add("RequestVerificationToken", AntiForgeryManager.GenerateToken()); // changed
}
}
Yes, I can reproduce the problem. I am opening an internal issue for this.
2023-06-02 09:35:45.969 +03:00 [ERR] An unhandled exception has occurred while executing the request.
System.NullReferenceException: Object reference not set to an instance of an object.
at Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Themes.LeptonX.Components.SideMenu.Toolbar.LanguageSwitch.ThemeLanguageInfoProvider.GetLanguageSwitchViewComponentModel()
at Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Themes.LeptonX.Components.Common.MobileGeneralSettings.MobileGeneralSettingsViewComponent.InvokeAsync()
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsyncCore(ObjectMethodExecutor executor, Object component, ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentHelper.InvokeCoreAsync(ViewComponentDescriptor descriptor, Object arguments)
at Volo.Abp.AspNetCore.Mvc.UI.Widgets.AbpViewComponentHelper.InvokeAsync(Type componentType, Object arguments)
at AYVEhCp6iK4h4mmxeYR.Oi2jqVpmF6RLaW8Jp6X.ExecuteAsync()
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.ViewViewComponentResult.ExecuteAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentHelper.InvokeCoreAsync(ViewComponentDescriptor descriptor, Object arguments)
at Volo.Abp.AspNetCore.Mvc.UI.Widgets.AbpViewComponentHelper.InvokeAsync(Type componentType, Object arguments)
at ERWIIxOFYGRoT95Rbss.n2uEpTO8cMNabKx1lh2.<>c__DisplayClass19_0.LOH71gICjA7wiGBOaY3.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
at ERWIIxOFYGRoT95Rbss.n2uEpTO8cMNabKx1lh2.ExecuteAsync()
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|28_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Volo.Abp.AspNetCore.Serilog.AbpSerilogMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Volo.Abp.AspNetCore.Uow.AbpUnitOfWorkMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.MultiTenancy.MultiTenancyMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Builder.ApplicationBuilderAbpOpenIddictMiddlewareExtension.<>c__DisplayClass0_0.<<UseAbpOpenIddictValidation>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Volo.Abp.AspNetCore.Security.AbpSecurityHeadersMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.Tracing.AbpCorrelationIdMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
The problem will be solved as soon as possible.
Do you need a workaround?
I will test your problem more but before that I have a small request.
If you haven't tried to get the Antiforgery token as follows, do you have a chance to try it?
@(Html.DevExtreme().FileUploader()
.OnInitialized("OnInitialized")
...
function OnInitialized(s, e) {
var _createFormData = s.component._uploadStrategy._createFormData;
s.component._uploadStrategy._createFormData = (fieldName, fieldValue) => {
var formData = _createFormData.call(this, fieldName, fieldValue);
formData.append('__RequestVerificationToken', document.getElementsByName("__RequestVerificationToken")[0].value);
return formData;
}
}
The codes I suggest are excerpts from here, so if you need more information on this, you can check it out here.
The reason I want you to try this is because I think you might have a similar situation with someone who is experiencing the same problem as you in different ways.
Please let me know the result :)
Hi,
The problem may not be related to ABP. Here are some support tickets from DevExpress:
I hope these resources solve your question. If you get stuck somewhere, don't hesitate to ask :)
Can you add the code below to your relevant page and try again?
@inject PageLayout PageLayout
@code {
protected override async Task OnInitializedAsync()
{
PageLayout.MenuItemName = "YourMenuItemName";
}
}
For more information, please visit this document.
Hello,
I recommend you to use the ABP widget system for your requirements like this. For example, we developed a wizard like the one below in EventHub:
You can find the relevant code here.
You can reach a similar view by creating a partial view for each page in the Wizard and using it in a page, widget or modal and changing the visibility of the partial view with javascript.