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,
I have removed WebDAVModule and not it is working. Also, I've done changes as image below:
source: https://stackoverflow.com/questions/12440277/how-do-i-enable-http-put-and-delete-for-asp-net-mvc-in-iis
My new Web.Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
<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-->
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've found in the class PermissionDefinitionProvider a parameter for each permission that defines the multiTenancySide. Does that mean to define the menu as well?
public class AvalancheOCPPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var myGroup = context.AddGroup(AvalancheOCPPermissions.GroupName);
myGroup.AddPermission(AvalancheOCPPermissions.Dashboard.Host, L("Permission:Dashboard"), MultiTenancySides.Host);
myGroup.AddPermission(AvalancheOCPPermissions.Dashboard.Tenant, L("Permission:Dashboard"), MultiTenancySides.Tenant);
var settings = context.AddGroup(AvalancheOCPPermissions.AvalancheOCPSettings, L("Menu:AvalancheOCPSettings"), MultiTenancySides.Tenant);
var causes = settings.AddPermission(AvalancheOCPPermissions.Causes.Default, L("Menu:Causes"), MultiTenancySides.Tenant);
causes.AddChild(AvalancheOCPPermissions.Causes.Create, L("Permission:Causes.Create"), MultiTenancySides.Tenant);
causes.AddChild(AvalancheOCPPermissions.Causes.Edit, L("Permission:Causes.Edit"), MultiTenancySides.Tenant);
causes.AddChild(AvalancheOCPPermissions.Causes.Delete, L("Permission:Causes.Delete"), MultiTenancySides.Tenant);
var supplyNetworks = settings.AddPermission(AvalancheOCPPermissions.SupplyNetworks.Default, L("Menu:SupplyNetworks"), MultiTenancySides.Tenant);
supplyNetworks.AddChild(AvalancheOCPPermissions.SupplyNetworks.Create, L("Permission:SupplyNetworks.Create"), MultiTenancySides.Tenant);
supplyNetworks.AddChild(AvalancheOCPPermissions.SupplyNetworks.Edit, L("Permission:SupplyNetworks.Edit"), MultiTenancySides.Tenant);
supplyNetworks.AddChild(AvalancheOCPPermissions.SupplyNetworks.Delete, L("Permission:SupplyNetworks.Delete"), MultiTenancySides.Tenant);
myGroup.AddPermission(AvalancheOCPPermissions.OutageReportsGrid.Default, L("Permission:OutageReportGrid"), MultiTenancySides.Tenant);
//Define your own permissions here. Example:
//myGroup.AddPermission(AvalancheOCPPermissions.MyPermission1, L("Permission:MyPermission1"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<AvalancheOCPResource>(name);
}
}
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"
));
}
}
Ok, I got it. Thank you!
Thank you for your answer.
That works fine when I am adding a new entity. When editing, it doesn't work, the Save button is disabled by default. I just have created a new OnStatusChanged method for editing adding the option None. See below the new method:
protected Task OnStatusChangedEditing(ValidationsStatusChangedEventArgs eventArgs)
{
saveDisabled = eventArgs.Status != ValidationStatus.None && eventArgs.Status != ValidationStatus.Success;
return Task.CompletedTask;
}
Hi, I am implemeting my first CRUD using AbpCrudPageBase class. I have two questions about that:
Is it allways required having two MODAL markup and repeat the fields? If the Create and Edit modal are exactly the same, do I need to repeat that?
In events onChange, I have two variables, NewEntity and EditingEntity. How I know if I am editing or creating a new record? The only way that I've found to resolve that was creating two different events and then duplicating code or creating a third method and pass the EntityDto as parameter.
For example, to load an image in the event <FileEdit Changed="">, I did the code below. Is there a better way to do that?
protected async Task OnChangedLogoNew(FileChangedEventArgs e)
{
await ChangedLogo(e, NewEntity);
}
protected async Task OnChangedLogoEditing(FileChangedEventArgs e)
{
await ChangedLogo(e, EditingEntity);
}
protected async Task ChangedLogo(FileChangedEventArgs e, CreateUpdateSupplyNetworkDto currentDto)
{
try
{
foreach (var file in e.Files)
{
// A stream is going to be the destination stream we're writing to.
using (var stream = new MemoryStream())
{
await file.WriteToStreamAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
currentDto.Logo = stream.ToArray();
}
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
finally
{
this.StateHasChanged();
}
}
Thank you very much! That works fine for me. I didn't notice that part of documents for ABP Framework > UI > Blazor before.