Hi,
Nowadays, when accessing the app it redirect for the home page where I am not using for nothing in my application. So, the user has to click in login to access the app. If he logout, I want to redirect to the login page. In other word, I don't want to use that Home page where there is no user logged. I want to go from Login to App (Host side or Tenant site), and then when logout or the session is expired redirecting to Login page, similar as AspNetZero does.
Is that possible? If don't, how can I require that as a framework feature?
ABP Framework version: v4.2.3 rc.1 UI type: Blazor DB provider: EF Core Tiered (MVC) or Identity Server Separated (Angular): yes / no Exception message and stack trace: Steps to reproduce the issue:
Hi,
If I have to extend the component DefaultLayout from Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components.ApplicationLayout, do I need to rewrite the whole markups elements or it will be inherited?
I was not able to inherited the elements, I had to rewrite them again. I don't want to do that because I just want to override the method OnInitialize().
My new components:
@using Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components.ApplicationLayout
@inherits DefaultLayout
@using Volo.Abp.Ui.Branding
@using Volo.Abp.BlazoriseUI.Components
@using Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components.ApplicationLayout.MainHeader
@using Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components.ApplicationLayout.MainFooter
@inject IBrandingProvider BrandingProvider
<MainHeader />
<div class="lp-content h-100">
<PageAlert />
@Body
<UiMessageAlert />
<UiNotificationAlert />
</div>
<MainFooterComponent />
That is the code that I don't want to have to rewrite. I would like that would be inherited from DefaultLayout as specified by @inherited DefaultLayout
Code-behind:
using Microsoft.AspNetCore.Components;
using System;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components.ApplicationLayout;
using Volo.Abp.DependencyInjection;
namespace TVD_Holdings_Ltd.AvalancheOCP.Blazor.Components.ApplicationLayout
{
[ExposeServices(typeof(DefaultLayout))]
[Dependency(ReplaceServices = true)]
public partial class DefaultLayoutExtension
{
[Inject] IConfiguration Configuration { get; set; }
[Inject] IAlertManager _alertManager { get; set; }
private HubConnection hubConnection;
protected override async Task OnInitializedAsync()
{
// Do something
}
}
}
Hi,
I need to hook up a SignalR event for every single page in my application. I was thinking to do that on the Layout page by method OnIntiliaze. However, the Layout code is not available, it is implemented in one of the NuGet packages and the only way to do that is by extending the razor component in my project and then creating the method.
I wonder if there is another way to do that?
In this scenario, the back-end will send a notification (disk full for example), and a toast/modal notification will be shown for users. Is there some example of how to do implement that?
Hi,
I am trying to add the Blaorise.SideBar package in the Abp.IO Blazor project, but it is not working. It seems that there is some version conflict.
I am following the steps as this document: https://blazorise.com/docs/extensions/sidebar/
The current version for Blazorise is 0.9.3-preview6. If I try to update that the project fails when initializing.
So, If I install the Blazorise.SideBar version 0.9.2.5 (the previous one before 0.9.3), the project loads but when using the SideBar component it craches.
What would I do to be able to use Blazorise.SideBar?
Hi,
I am creating most of my entities descending from the clas AuditedAggregateRoot. It implements the field CreationTime and LastModificationTime. Using Postgres database and Entity Framework Code First, it is creating those fields as Timestamp without timezone. In my opinion, it should be with timezone instead.
I realized that if a class is defined as DateTime, Npgsql will create that field as "timestamp without timezone". However, if the field is defined as DateTimeOffset, then it creates as "timestamp with timezone".
I think I have basically two options to deal with that:
builder.Entity<Cause>(b => {
b.ToTable("Causes");
b.ConfigureByConvention();
b.Property(x => x.CreationTime).HasColumnType("timestamp with time zone");
b.Property(x => x.LastModificationTime).HasColumnType("timestamp with time zone");
});
public partial class Create_Cause : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Causes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Name = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
DefaultCause = table.Column<bool>(type: "boolean", nullable: false),
MarkerColor = table.Column<int>(type: "integer", nullable: false),
MakerType = table.Column<int>(type: "integer", nullable: false),
ExtraProperties = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: true),
// Before
// CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
// After
CreationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
// LastModificationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Causes", x => x.Id);
});
}
I am not sure if there is other way to do that. Do you think will be a solution in the framework for this issue in future? What is recommended to do at this situation?
Hi,
I have a global system, it will be used in Canada, USA, Australia, and New Zealand, and I am trying to understand how ABP.IO Blazor UI template works with timezone with Entity Framework Core and PostGres database.
I am familiar how Boilerplate works with timezone with AspNetZero MVC .NetCore + JQuery. However, I am struggling to understand how I should implement that in ABP.IO Blazor Template. I have already read this document: https://docs.abp.io/en/abp/latest/Timing
I was wondering if there is some binders and converter for Web API methods similar as implemented by Boilerplate. See this document: https://aspnetboilerplate.com/Pages/Documents/Timing#binders-and-converters
Is there some example how to deal with timezones for Blazor template, in both ways, going from the client to the database and then from the database back to the client?
Hi,
I am using Telerik components in my project and I am trying to use a Server Filtering. To be able to do that, I need to send a parameter from Blazor side to Application Service to filter/sort/group my records as per the grid parameters.
It is working fine, but, when I add some filter, it is raising an exception on Blazor side before calling the method in the Application Service. I am struggling to understand what is wrong with that.
Here is the error in the console:
My Application Service:
[HttpPost]
public async Task<DataEnvelope<OutageReportDto>> GetOutageReportList([FromBody] DataSourceRequest request)
{
try
{
var time = DateTime.UtcNow.AddDays(-1);
var outageList = _outageReportRepository
.Include(x => x.SupplyNetwork).Include(x => x.Cause)
.Where(x => x.TenantId == CurrentTenant.Id.Value)
.Where(x => x.RecordedTime >= time)
.Select(x => ObjectMapper.Map<OutageReport, OutageReportDto>(x)).ToList();
var output = await outageList.ToDataSourceResultAsync(request);
DataEnvelope<OutageReportDto> dataToReturn;
if (request.Groups != null && request.Groups.Count > 0)
{
// If there is grouping, use the field for grouped data
// The app must be able to serialize and deserialize it
// Example helper methods for this are available in this project
// See the GroupDataHelper.DeserializeGroups and JsonExtensions.Deserialize methods
dataToReturn = new DataEnvelope<OutageReportDto>
{
GroupedData = output.Data.Cast<AggregateFunctionsGroup>().ToList(),
TotalItemCount = output.Total
};
}
else
{
// When there is no grouping, the simplistic approach of
// just serializing and deserializing the flat data is enough
dataToReturn = new DataEnvelope<OutageReportDto>
{
CurrentPageData = output.Data.Cast<OutageReportDto>().ToList(),
TotalItemCount = output.Total
};
}
return dataToReturn;
}
catch (Exception ex)
{
Console.WriteLine("Error: ", ex.Message);
Console.WriteLine(ex);
throw;
}
}
My Blazor page code behind code:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Telerik.Blazor.Components;
using Telerik.DataSource;
using TVD_Holdings_Ltd.AvalancheOCP.AOR.OutageReports;
namespace TVD_Holdings_Ltd.AvalancheOCP.Blazor.Pages.AOR
{
public class OutageReportGridBase : ComponentBase
{
[Inject] IOutageReportAppService outageReportService { get; set; }
[Inject] IConfiguration Configuration { get; set; }
[Inject] HttpClient httpClient { get; set; }
//
protected TelerikGrid<object> MainGrid { get; set; }
protected List<object> OutageReportList { get; set; }
protected int Total { get; set; }
//
private HubConnection hubConnection;
private DataSourceRequest LastRequest;
protected override async Task OnInitializedAsync()
{
var baseUrl = Configuration.GetValue<string>("RemoteServices:Default:BaseUrl");
hubConnection = new HubConnectionBuilder()
.WithUrl(baseUrl + "/aor")
.Build();
hubConnection.On("OutagesUpdated", LoadData);
await hubConnection.StartAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await SetGridDefaultSort();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task SetGridDefaultSort()
{
GridState<object> desiredState = new GridState<object>()
{
SortDescriptors = new List<SortDescriptor>()
{
new SortDescriptor { Member = nameof(OutageReportDto.RecordedTime), SortDirection = ListSortDirection.Descending }
}
};
await MainGrid.SetState(desiredState);
}
private async Task LoadData()
{
var result = await outageReportService.GetOutageReportList(LastRequest);
if (LastRequest.Groups.Count > 0)
{
var data = GroupDataHelpers.DeserializeGroups<OutageReportDto>(result.GroupedData);
OutageReportList = data.Cast<object>().ToList();
}
else
{
OutageReportList = result.CurrentPageData.Cast<object>().ToList();
}
Total = result.TotalItemCount;
StateHasChanged();
}
protected async Task OnReadHandler(GridReadEventArgs args)
{
LastRequest = args.Request;
await LoadData();
}
}
}
And my Blazor Page:
@page "/outagereports"
@attribute [Authorize(AvalancheOCPPermissions.OutageReportsGrid.Default)]
@using TVD_Holdings_Ltd.AvalancheOCP.Permissions
@using Microsoft.AspNetCore.Authorization
@using TVD_Holdings_Ltd.AvalancheOCP.Localization
@using Microsoft.Extensions.Localization
@using TVD_Holdings_Ltd.AvalancheOCP.AOR.OutageReports;
@inject IStringLocalizer<AvalancheOCPResource> L
@inject AbpBlazorMessageLocalizerHelper<AvalancheOCPResource> LH
@inherits OutageReportGridBase
<Card>
<CardHeader>
<Row Class="justify-content-between">
<Column ColumnSize="ColumnSize.IsAuto">
<h2>@L["OutageReportGrid"]</h2>
</Column>
</Row>
</CardHeader>
<CardBody>
<TelerikRootComponent>
<TelerikGrid Data=@OutageReportList @ref="@MainGrid"
OnRead="@OnReadHandler" TotalCount=@Total
Sortable="true"
Groupable="true"
FilterMode="@GridFilterMode.FilterMenu"
Pageable="true" PageSize="50">
<GridColumns>
<GridColumn Field="@nameof(OutageReportDto.SupplyNetworkName)" FieldType="@(typeof(string))" Title="@L["OutageReportGrid.SupplyNetworkName"]"/>
<GridColumn Field="@nameof(OutageReportDto.RecordedTime)" FieldType="@(typeof(DateTime))" Title="@L["OutageReportGrid.RecordedTime"]" DisplayFormat="{0:ddd dd-MMM-yyyy HH:mm}" />
<GridColumn Field="@nameof(OutageReportDto.CreationTime)" FieldType="@(typeof(DateTime))" Title="@L["OutageReportGrid.CreationTime"]" DisplayFormat="{0:ddd dd-MMM-yyyy HH:mm}"/>
<GridColumn Field="@nameof(OutageReportDto.NotifiedTime)" FieldType="@(typeof(DateTime?))" Title="@L["OutageReportGrid.NotifiedTime"]" DisplayFormat="{0:ddd dd-MMM-yyyy HH:mm}" />
<GridColumn Field="Location" FieldType="@(typeof(string))" Title="@L["OutageReportGrid.Location"]" />
<GridColumn Field="@nameof(OutageReportDto.Suburb)" FieldType="@(typeof(string))" Title="@L["OutageReportGrid.Suburb"]" />
<GridColumn Field="@nameof(OutageReportDto.CauseName)" FieldType="@(typeof(string))" Title="@L["OutageReportGrid.CauseName"]" />
<GridColumn Field="@nameof(OutageReportDto.ContactPhoneNumber)" FieldType="@(typeof(string))" Title="@L["OutageReportGrid.ContactPhoneNumber"]" />
</GridColumns>
</TelerikGrid>
</TelerikRootComponent>
</CardBody>
</Card>
Hi,
In my local machine all CRUD operations work fine. But, when I deploy to IIS Server the Update and Delete don't work.
I've tried to remove WebDAV in the Web.Config, but still getting errors. My Web.Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
<remove name="WebDAV" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\TVD_Holdings_Ltd.AvalancheOCP.HttpApi.Host.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
</system.webServer>
</location>
</configuration>
<!--ProjectGuid: 96e5259e-59a3-4faf-bcd1-5bf8e74ef82c-->
In the console I am getting these messages:
What should I change in my config to make it work?
Hi,
I'd like to know how to perform orderby passing a string as parameter when I have two tables connect by join in the method GetListAsync in a CrudAppService class.
In the Tutorial, Item 10. Book and Author Relation, in the method GetListAsync we have this comment:
orderby input.Sorting //TODO: Can not sort like that!
In AspNetZero project I have an extension for OrderBy and PageBy that make life easy. But, I haven't found those extensions for Abp.IO Blazor UI project.
Here is my code:
public override async Task<PagedResultDto<SupplyNetworkDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
//Set a default sorting, if not provided
if (input.Sorting.IsNullOrEmpty())
{
input.Sorting = nameof(SupplyNetworkDto.Name);
}
//Get the IQueryable<Book> from the repository
var queryable = await Repository.GetQueryableAsync();
//Prepare a query to join books and authors
var query = from supplyNetwork in queryable
join networkType in _networkTypeRepository on supplyNetwork.NetworkTypeId equals networkType.Id
orderby input.Sorting // It is not working as per example in ABP.IO Documentation Example
select new { supplyNetwork, networkType };
query = query
.Skip(input.SkipCount)
.Take(input.MaxResultCount);
//Execute the query and get a list
var queryResult = await AsyncExecuter.ToListAsync(query);
//Convert the query result to a list of BookDto objects
var dtos = queryResult.Select(x =>
{
var dto = ObjectMapper.Map<SupplyNetwork, SupplyNetworkDto>(x.supplyNetwork);
dto.NetworkTypeName = x.networkType.Name;
return dto;
}).ToList();
//Get the total count with another query
var totalCount = await Repository.GetCountAsync();
return new PagedResultDto<SupplyNetworkDto>(
totalCount,
dtos
);
}
Hi, I have added two menus that should be visible only in the Tenant Side. I don't want then on the Host side. How can I do that?
I tried to inject CurrentTenant and check the property IsAvailable, but, the class is instanced manually and dependency injection doesn't work. See my code below:
public class AvalancheOCPMenuContributor : IMenuContributor
{
private readonly IConfiguration _configuration;
public AvalancheOCPMenuContributor(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
await ConfigureMainMenuAsync(context);
}
else if (context.Menu.Name == StandardMenus.User)
{
await ConfigureUserMenuAsync(context);
}
}
//This method was intentionally "async" because ABP Suite will generate asnyc method calls here.
private static async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.GetLocalizer<AvalancheOCPResource>();
context.Menu.AddItem(new ApplicationMenuItem(
AvalancheOCPMenus.Home,
l["Menu:Home"],
"/",
icon: "fas fa-home",
order: 1
));
// Tenant Side
**//if (_currentTenant.IsAvailable) // How to do it? Or what is the best way to do that?**
{
var settings = new ApplicationMenuItem(
"Settings",
l["Menu:AvalancheOCPSettings"],
icon: "fa fa-sliders",
order: 2
);
context.Menu.AddItem(settings);
if (await context.IsGrantedAsync(AvalancheOCPPermissions.Causes.Default))
{
settings.AddItem(new ApplicationMenuItem(
"Settings.Causes",
l["Menu:Causes"],
url: "/causes"
));
}
if (await context.IsGrantedAsync(AvalancheOCPPermissions.SupplyNetworks.Default))
{
settings.AddItem(new ApplicationMenuItem(
"Settings.SupplyNetworks",
l["Menu:SupplyNetworks"],
url: "/supplynetworks"
));
}
}