Saritasa.NetForge
0.4.4-alpha
dotnet add package Saritasa.NetForge --version 0.4.4-alpha
NuGet\Install-Package Saritasa.NetForge -Version 0.4.4-alpha
<PackageReference Include="Saritasa.NetForge" Version="0.4.4-alpha" />
paket add Saritasa.NetForge --version 0.4.4-alpha
#r "nuget: Saritasa.NetForge, 0.4.4-alpha"
// Install Saritasa.NetForge as a Cake Addin #addin nuget:?package=Saritasa.NetForge&version=0.4.4-alpha&prerelease // Install Saritasa.NetForge as a Cake Tool #tool nuget:?package=Saritasa.NetForge&version=0.4.4-alpha&prerelease
NetForge - Admin Panel for ASP.NET Core 6 & 7 & 8
The NetForge is a library that provides a user-friendly and intuitive user interface for performing CRUD operations on your database entities within your .NET applications.
- NetForge - Admin Panel for ASP.NET Core 6 & 7 & 8
- How to Use
- Global Configurations
- Customizing Entities
- Customizing Entity Properties
- Fluent API
- Data Attributes
- Display Formatting
- Data Sorting
- Calculated Properties
- Display Properties as Title Case
- Default Values
- Navigation Properties
- Exclude All Properties and Include Specific Only
- Exclude Property from Query
- Formatting Property as HTML
- Generated Properties
- Rich Text Field
- Image Properties
- Read-only Properties
- String Truncate
- Multiline Text Field Property
How to Use
Add NetForge to your service collection in Program.cs
:
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.UseEntityFramework(efOptionsBuilder =>
{
efOptionsBuilder.UseDbContext<MyDbContext>();
});
...
});
Make your application to use the admin panel:
app.UseNetForge();
Global Configurations
Customizing the Endpoint
By default, NetForge Admin is running on /admin but you can configure to use your custom endpoint like this:
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.UseEndpoint("/manage");
...
});
Customizing the Title
You can customize the header title like this:
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.SetHeaderTitle("title");
...
});
And customize the HTML title like this:
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.SetHtmlTitle("title");
...
});
Configuring Authorization
You can customize the access policy by requiring specific Identity roles:
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.AddAccessRoles("Role1", "Role2", "Role3");
...
});
Alternatively, you can use a custom function to perform authorization checks. Example:
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.ConfigureAuth(serviceProvider =>
{
// Allow all authenticated users to see the Admin Panel.
var httpContext = serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
return Task.FromResult(httpContext?.User.Identity?.IsAuthenticated ?? false);
});
});
Search
You can read about search here.
View Site URL
Located in the top right corner of the admin panel is a "View Site" link, configurable to direct users to the website URL. The default URL is "/". You can customize this value using the Fluent API:
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.ConfigureUrl("https://www.example.com/");
});
Grouping
Group rows of entities into categories and make it easier for users to navigate and understand the data presented.
Customizing the UI
Main Layout Overriding
You can override the default layout of the admin panel. To do this, create a new layout in your host project and specify its type in the configuration.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.SetCustomLayout(typeof(CustomLayout));
});
Your custom layout should inherit from the AdminBaseLayout
class.
The example of the custom component with navigation bar and footer:
@using MudBlazor
@inherits Saritasa.NetForge.Blazor.Shared.AdminBaseLayout
<MudThemeProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<MudAppBar Color="Color.Primary" Elevation="4">
<MudText Typo="Typo.h6">My Application</MudText>
<MudSpacer />
<MudNavMenu>
<MudNavLink Href="/about">About</MudNavLink>
<MudNavLink Href="/contact">Contact</MudNavLink>
</MudNavMenu>
</MudAppBar>
@Body
<footer>
<MudPaper Class="pa-4" Elevation="4">
<MudText Typo="Typo.body2">My Application</MudText>
<MudSpacer />
<MudNavMenu>
<MudNavLink Href="/privacy">Privacy Policy</MudNavLink>
<MudNavLink Href="/terms">Terms of Service</MudNavLink>
</MudNavMenu>
</MudPaper>
</footer>
Create Groups for Entities
Before assigning entities to specific groups, users need to define the groups to which the entities will belong.
To create a new group, utilize the Fluent API through AdminOptionsBuilder
. A name is required for each group, and a description is optional.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.UseEntityFramework(efOptionsBuilder =>
{
efOptionsBuilder.UseDbContext<ShopDbContext>();
}).AddGroups(new List<EntityGroup>
{
new EntityGroup{ Name = "Product", Description = "Contains all information related to products" },
new EntityGroup{ Name = "Shop"}
}).ConfigureEntity<Shop>(entityOptionsBuilder =>
{
entityOptionsBuilder.SetDescription("The base Shop entity.");
});
});
Configuration
By default, entities are assigned to the "empty" group. Grouping can be customized either through the Fluent API or by using attributes. When assigning entities to a group, users only need to specify the group's name. If user specifies a group that does not exists for an entity, that entity will belong to the default group.
Fluent API:
By utilizing EntityOptionsBuilder
, user can set group for entity using group's name.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.UseEntityFramework(efOptionsBuilder =>
{
efOptionsBuilder.UseDbContext<ShopDbContext>();
}).AddGroups(new List<EntityGroup>
{
new EntityGroup{ Name = "Product", Description = "Contains all information related to products" },
new EntityGroup{ Name = "Shop"}
}).ConfigureEntity<Shop>(entityOptionsBuilder =>
{
entityOptionsBuilder.SetGroup("Shop");
entityOptionsBuilder.SetDescription("The base Shop entity.");
});
});
Data Attribute:
[NetForgeEntity(GroupName = "Product")]
public class ProductTag
Headers Expansion
You can customize expanded header of all groups. By default, all groups are expanded.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.SetGroupHeadersExpanded(true);
});
Exclude All Entities and Include Specific Only
You can exclude all entities and include only specific ones.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.ExcludeAllEntities();
optionsBuilder.IncludeEntities(typeof(Shop), typeof(Product));
});
Or you can include specific entities using the data attribute:
[NetForgeEntity]
public class Shop
Customizing Entities
In the admin panel, you can customize the way entities are displayed using the Fluent API or special attribites. This enables you to set various properties for your entities, such as their name, description, plural name, etc.
Fluent API
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.UseEntityFramework(efOptionsBuilder =>
{
efOptionsBuilder.UseDbContext<MyDbContext>();
});
// Set the description to display for the Shop entity.
optionsBuilder.ConfigureEntity<Shop>(entityOptionsBuilder =>
{
entityOptionsBuilder.SetDescription("Represents the shop.");
});
// Hide ProductTag from the admin panel.
optionsBuilder.ConfigureEntity<ProductTag>(entityOptionsBuilder =>
{
entityOptionsBuilder.SetIsHidden(true);
});
});
Creating an Entity Configuration Class
To reduce the amount of the code all configuration for an entity type can also be extracted to a separate class.
To create an entity configuration for a specific entity type, create a new class that implements the IEntityAdminConfiguration<TEntity>
interface, where TEntity
is the type of the entity you want to configure. For example, if you want to configure the Product
entity, your class might look like this:
public class ProductAdminConfiguration : IEntityAdminConfiguration<Product>
{
public void Configure(EntityOptionsBuilder<Product> builder)
{
// Define entity-specific settings here.
}
}
// Add this to your Program.cs.
appBuilder.Services.AddNetForge(optionsBuilder =>
{
optionsBuilder.ConfigureEntity(new ProductAdminConfiguration());
// Other settings...
});
Data Attributes
You can also customize your entities by applying special attributes directly to your entity classes.
NetForgeEntityAttribute
[NetForgeEntity(DisplayName = "Entity", PluralName = "Entities", Description = "This is an entity description.")]
public class Entity
{
// Entity properties...
}
You can use the built-in System.ComponentModel.DescriptionAttribute
and System.ComponentModel.DisplayNameAttribute
to specify descriptions and display names for your entity classes.
For example:
[Description("Custom entity description.")]
[DisplayName("Custom Entity Display Name")]
public class AnotherEntity
{
// Entity properties...
}
Custom Query
You can configure your query for specific entity.
.ConfigureEntity<Shop>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureCustomQuery((serviceProvider, query) =>
{
return query.Where(e => e.IsOpen == true);
});
})
After Update Action
You can configure action that will be performed after entity update.
.ConfigureEntity<Address>(entityOptionsBuilder =>
{
entityOptionsBuilder.SetAfterUpdateAction((serviceProvider, originalEntity, modifiedEntity) =>
{
var dbContext = serviceProvider!.GetRequiredService<ShopDbContext>();
const string country = "Germany";
if (originalEntity.Country == country)
{
return;
}
if (modifiedEntity.Country == country)
{
modifiedEntity.PostalCode = "99998";
}
dbContext.SaveChanges();
});
})
You can use ServiceProvider
to access your services.
Customizing Entity Properties
You can customize entity properties as well. For example, you can change display name, add description, hide it or change property column order.
Fluent API
optionsBuilder.ConfigureEntity<Address>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureProperty(address => address.Id, propertyBuilder =>
{
propertyBuilder
.SetDescription("Item identifier.")
.SetOrder(2);
});
entityOptionsBuilder.ConfigureProperty(address => address.ContactPhone, propertyBuilder =>
{
propertyBuilder
.SetDisplayName("Phone")
.SetDescription("Address contact phone.")
.SetOrder(1);
});
entityOptionsBuilder.ConfigureProperty(address => address.PostalCode, propertyBuilder =>
{
propertyBuilder.SetIsHidden(true);
});
entityOptionsBuilder.ConfigureProperty(address => address.City, propertyBuilder =>
{
propertyBuilder.SetDisplayName("Town");
});
});
Data Attributes
Properties also customizable via attributes.
NetForgeEntityAttribute
[NetForgeProperty(DisplayName = "Custom property display name", Description = "Custom property description.", Order = 5)]
public string Property { get; set; }
Built-in Description
and DisplayName
Attributes
[Description("Custom property description.")]
[DisplayName("Custom property display name")]
public string Property { get; set; }
Display Formatting
You can configure the display format for the properties values. See string.Format.
Using Data Attributes
You can apply the [NetForgeProperty]
attribute to an entity property and specify the display format:
[NetForgeProperty(DisplayFormat = "{0:C}")]
public decimal Price { get; set; }
In this example, the Price property will be displayed using the currency format.
Using Fluent API
Alternatively, you can use the Fluent API to configure the display format and format provider for an entity property:
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.ConfigureEntity<Product>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureProperty(product => product.Price, propertyBuilder =>
{
propertyBuilder.SetDisplayFormat("{0:C}");
// Use Euro as a currency.
propertyBuilder.SetFormatProvider(CultureInfo.GetCultureInfo("fr-FR"));
});
});
// Other settings...
});
Data Sorting
You can apply alphabet sorting to some properties. By default, they are not sortable.
It is configurable via [NetForgeProperty]
and Fluent API
.
Using Data Attribute
[NetForgeProperty(IsSortable = true)]
public string Name { get; set; }
Using Fluent API
entityOptionsBuilder.ConfigureProperty(shop => shop.OpenedDate, builder =>
{
builder.SetIsSortable(true);
});
You can sort multiple properties at once. It can be achieved by pressing sort buttons with CTRL
.
Sorting can be cancelled by pressing on it with ALT
.
Calculated Properties
Calculated properties are properties that don't have a direct representation in your database but are computed based on other existing properties. These properties can be useful for displaying calculated values in the admin panel.
You can add calculated properties to your entities using the Fluent API:
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.ConfigureEntity<User>(entityOptionsBuilder =>
{
entityOptionsBuilder.AddCalculatedProperties(user => user.FullName, user => user.Age);
});
// Other settings...
});
Display Properties as Title Case
By default, all entity properties are displayed in Title Case.
For example, the Product
entity will have the property StockQuantity
. By default, it will be displayed as Stock Quantity
in the admin panel.
This behavior can be disabled, and the entities will use CamelCase display instead.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.DisableTitleCaseProperties();
});
Default Values
Users can customize the value used for displaying the empty record values. By default, it will be displayed as "-" (a dash).
Using Fluent API
optionsBuilder.ConfigureEntity<User>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureProperty(user => user.DateOfBirth,
propertyBuilder => propertyBuilder.SetEmptyValueDisplay("N/A"));
});
Using Attribute
[NetForgeProperty(EmptyValueDisplay = "N/A")]
public string Property { get; set; }
Navigation Properties
You can read about navigation properties here.
Exclude All Properties and Include Specific Only
You can exclude all properties and include only specific ones. It works with both ordinary and navigation properties.
Using Fluent API
optionsBuilder.ConfigureEntity<User>(entityOptionsBuilder =>
{
entityOptionsBuilder.ExcludeAllProperties();
entityOptionsBuilder.IncludeProperties(user => user.Id, user => user.Name);
});
Or you can include specific properties using the Attribute:
[NetForgeProperty]
public string Property { get; set; }
Exclude Property from Query
You can explicitly control whether a property should be excluded from the data query.
Using Fluent API
optionsBuilder.ConfigureEntity<User>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureProperty(user => user.DateOfBirth,
propertyBuilder => propertyBuilder.SetIsExcludedFromQuery(true));
});
Using Data Attribute
[NetForgeProperty(IsExcludeFromQuery = true)]
public string Property { get; set; }
Formatting Property as HTML
You can configure certain entity properties to be rendered as HTML content in the data grid. This feature ensures that HTML tags within these properties are not escaped, allowing for richer and more dynamic data presentation.
Using Fluent API
optionsBuilder.ConfigureEntity<User>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureProperty(user => user.Id,
propertyBuilder => propertyBuilder.SetDisplayAsHtml(true));
});
Using Data Attribute
[NetForgeProperty(DisplayAsHtml = true)]
public string Property { get; set; }
Generated Properties
Generated properties will not be displayed on the create or edit entity pages. Entity framework example of generated property:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime CreatedAt { get; set; }
Rich Text Field
RTF provides some common text formatting options like paragraphs, links, tables, etc. The ClassicEditor of CKEditor 5 is used by the admin panel.
The configuration is the following:
Using Data Attribute
[NetForgeProperty(IsRichTextField = true)]
public required string Description { get; set; }
Using Fluent API
optionsBuilder.ConfigureEntity<Product>(entityOptionsBuilder =>
{
entityOptionsBuilder.ConfigureProperty(product => product.Description,
propertyBuilder => propertyBuilder.SetIsRichTextField(true));
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime CreatedAt { get; set; }
Image Properties
You can add properties that will be displayed as images.
Configuration
Using Fluent API
You can create your own implementaion of IUploadFileStrategy
interface and pass it to SetUploadFileStrategy
configuration method.
This interface has methods UploadFileAsync
that is calling when file is uploaded and GetFileSource
that is calling when file should be displayed.
We have some examples of strategies here.
entityOptionsBuilder.ConfigureProperty(shop => shop.BuildingPhoto, builder =>
{
builder
.SetIsImage(true)
.SetUploadFileStrategy(new UploadBase64FileStrategy());
});
Max image size
You can set max image size in the application. Default value for max image size is 10 MB.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.SetMaxImageSize(15);
});
Read-only Properties
You can mark a property as read only. Such property cannot be changed on create and edit pages.
Configuration
Using Fluent API
entityOptionsBuilder.ConfigureProperty(product => product.UpdatedDate, builder =>
{
builder.SetIsReadOnly(true);
});
Using Data Attribute
[NetForgeProperty(IsReadOnly = true)]
public string Property { get; set; }
String Truncate
You can set the max characters amount for string properties.
Configuration
Global
You can set max characters for the all strings. Default value is 50.
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.SetTruncationMaxCharacters(60);
});
You can disable this behavior in this way:
services.AddNetForge(optionsBuilder =>
{
optionsBuilder.DisableCharactersTruncation();
});
For the Property
You can set max characters to each property individually.
Using Data Attribute
[NetForgeProperty(TruncationMaxCharacters = 20)]
public string Name { get; set; }
Using Fluent API
entityOptionsBuilder.ConfigureProperty(shop => shop.Name, builder =>
{
builder.SetTruncationMaxCharacters(25);
});
Multiline Text Field Property
You can mark a property as multiline text field. It allows input of text in several text rows. Disabled by default.
Configuration
Using Fluent API
entityOptionsBuilder.ConfigureProperty(address => address.Street, builder =>
{
builder.SetIsMultiline();
});
Using Data Attribute
[MultilineText]
public required string Street { get; set; }
Also, there are some auxiliary properties that are used in the multiple text field.
Number of lines
Using Fluent API
entityOptionsBuilder.ConfigureProperty(address => address.Street, builder =>
{
builder.SetIsMultiline(lines: 15); // sets the lines value as 15
});
Using Data Attribute
[MultilineText(Lines = 15)]
public required string Street { get; set; }
Max Number of Lines
Using Fluent API
entityOptionsBuilder.ConfigureProperty(address => address.Street, builder =>
{
builder.SetIsMultiline(maxLines: 15); // sets the max lines value as 15
});
Using Data Attribute
[MultilineText(MaxLines = 15)]
public required string Street { get; set; }
Auto Grow
IsAutoGrow
property identifies whether the height of the text field automatically changes with the number of lines of text.
Using Fluent API
entityOptionsBuilder.ConfigureProperty(address => address.Street, builder =>
{
builder.SetIsMultiline(autoGrow: true);
});
Using Data Attribute
[MultilineText(IsAutoGrow = true)]
public required string Street { get; set; }
Contributors
- Saritasa http://www.saritasa.com
License
The project is licensed under the terms of the BSD license. Refer to LICENSE.txt for more information.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- CommunityToolkit.Mvvm (>= 8.2.2)
- Microsoft.AspNetCore.Components (>= 6.0.16)
- Microsoft.EntityFrameworkCore (>= 6.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 6.0.0)
- Microsoft.Extensions.Caching.Abstractions (>= 7.0.0)
- MudBlazor (>= 6.3.0)
- Newtonsoft.Json (>= 13.0.3)
- PluralizeService.Core (>= 1.2.21147.2)
- Saritasa.Tools.Common (>= 3.0.0)
-
net7.0
- CommunityToolkit.Mvvm (>= 8.2.2)
- Microsoft.AspNetCore.Components (>= 7.0.5)
- Microsoft.EntityFrameworkCore (>= 7.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 7.0.0)
- Microsoft.Extensions.Caching.Abstractions (>= 7.0.0)
- MudBlazor (>= 6.3.0)
- Newtonsoft.Json (>= 13.0.3)
- PluralizeService.Core (>= 1.2.21147.2)
- Saritasa.Tools.Common (>= 3.0.0)
-
net8.0
- CommunityToolkit.Mvvm (>= 8.2.2)
- Microsoft.AspNetCore.Components (>= 8.0.0)
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.0)
- Microsoft.Extensions.Caching.Abstractions (>= 8.0.0)
- MudBlazor (>= 6.12.0)
- Newtonsoft.Json (>= 13.0.3)
- PluralizeService.Core (>= 1.2.21147.2)
- Saritasa.Tools.Common (>= 3.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.4.4-alpha | 50 | 11/11/2024 |
0.4.3-alpha | 102 | 10/18/2024 |
0.4.2-alpha | 46 | 10/17/2024 |
0.4.1-alpha | 46 | 10/15/2024 |
0.4.0-alpha | 40 | 10/15/2024 |