Base solution for your next web application

Activities of "BigCDogCrew"

I have managed to corrupt some of the files in the metronic folderof my ASP.NET Zero MVC prroject and I want to rebuild the folder structure by downloading the current version (6.0.6).

For the sake of future readers..let's assume that all projects within the ASP.NET Zero solution need to be updated.

What is the process for updating the Metronic template in the MVC project?
Which folders and files do I need to copy from the Metronic ZIP file and into which folders do I place them?

How can I access a custom session from the client-side razor script?

The information in my database is structured like a supply chain. Some, but not all, information that tenants create must be available to other tenants down-stream. I have used the OrganizationUnits to construct the relationships between the tenants. I have also created custom filters that work with the OrganizationUnits, such as IncludeTenantChildren, IncludeTenantParent, IncludeTenantBranch, etc.

As I am now working on the more intricate details of my queries, I am finding that there are many times where an initial table determines what data should be seen by a tenant and then other subsequent tables are included in the query to provide additional details. However, those additional details in those subsequent tables come from data maintained by other tenants. Therefore, I need a simple way to state that the TenantId Filter should be applied only to a specific set (0 or more) of tables in the query and the other tables in the query should be treated as if the TenantId filters have been disabled.

As an example, a tenant may create a Package and then transfer the package to another tenant within their Organization. The TenantId on the Package table gets updated to the new tenant during the transfer process. Now, assume that there are two other tables, PackageContent and PackageTracking which both are linked to Package by PackageId. Data in the PackageContent table should be available only to the creator of the package and the recipient of the package. Data in the PackageTracking table should be available to anyone currently holding tenancy of the package.

So you see...having a TenantId filter that applies to all tables in the query will prevent the package recipient from seeing the PackageContent create by a different tenent. And each tenant will be able to see only the tracking records that they create themselves; not the full tracking history.

What's the best way to selectively apply the TenantId to specific tables (such as Package) and then ignore the TenantId filter on other tables (such as PackageContent and PackageTracking)? It is safe to assume that my custom filters are determining when/if it is appropriate to show PackageContent to the recipient.

What tool did the AspNetZero team use to produce the documentation website? https://docs.aspnetzero.com/en/common/latest

ScrollX does not appear to work. I'm using AspNetZero v8.6 MVC/jQuery. I am using no custom scripts or css. My sample code and result image are shown below.

What am I doing wrong?

var dataTable = _$peripheralsTable.DataTable({
	scrollX: true,
	paging: true,
	serverSide: true,
	processing: true,
	listAction: {
		ajaxFunction: _peripheralsService.getAll,
		inputFilter: function () {
			return {
				filter: $('#PeripheralsTableFilter').val(),
			};
		}
	},
	columnDefs: [{
		width: 120,
		targets: 0,
		data: null,
		orderable: false,
		autoWidth: false,
		defaultContent: '',
		rowAction: {
			cssClass: 'btn btn-brand dropdown-toggle',
			text: '<i class="fa fa-cog"></i> ' + app.localize('Actions') + ' <span class="caret"></span>',
			items: [
			{
				text: app.localize('View'),
				action: function (data) {
					_viewPeripheralModal.open({ id: data.record.peripheral.id });
				}
			},
			{
				text: app.localize('Edit'),
				visible: function () {
					return _permissions.edit;
				},
				action: function (data) {
					_createOrEditModal.open({ id: data.record.peripheral.id });
				}
			}]
		}
	},
	{
		targets: 1,
		visible: false,
		data: "peripheral.uid",
		name: "uid"   	
	},
	{
		targets: 2,
		data: "peripheral.serialNumber",
		name: "serialNumber"   
	},
	{
		targets: 3,
		data: "peripheral.assetTag",
		name: "assetTag"   
	},
	{
		targets: 4,
		data: "peripheral.firmwareVersion",
		name: "firmwareVersion"
	},
	{
		targets: 5,
		data: "peripheralModelCode" ,
		name: "peripheralModelFk.code" 
	}]
});

I'm using AspNetZero v8.6 MVC/jQuery and I'm trying to get a datatable to sort using multiple, user-selected columns.

The image below shows a table where the Name column was clicked (generating an ascending ordered list by name). Subsequently, the Code column was clicked twice while the shift key was depressed (causing the sort arrows to cycle from ascending to descending on that column).

Here is the javascript that feeds the datatable. I have collapsed the columnDef code a little to preserve length...

        var dataTable = _$addressEMailTypesTable.DataTable({
            scrollX: true,
            responsive: false,
            paging: true,
            serverSide: true,
            processing: true,
            listAction: {
                ajaxFunction: _addressEMailTypesService.getAll,
                inputFilter: function () {
                    return {
					    filter: $('#AddressEMailTypesTableFilter').val(),
					    nameFilter: $('#NameFilterId').val(),
					    codeFilter: $('#CodeFilterId').val()
                    };
                }
            },
            columnDefs: [
                {
                    width: 120,
                    targets: 0,
                    data: null,
                    orderable: false,
                    autoWidth: false,
                    defaultContent: '',
                    rowAction: {
                        cssClass: 'btn btn-brand dropdown-toggle',
                        text: '<i class="fa fa-cog"></i> ' + app.localize('Actions') + ' <span class="caret"></span>',
                        items: [
						    { text: app.localize('View'), action: function (data) { _viewAddressEMailTypeModal.open({ id: data.record.addressEMailType.id }); } },
						    { text: app.localize('Edit'), visible: function () { return _permissions.edit; }, action: function (data) { _createOrEditModal.open({ id: data.record.addressEMailType.id }); } }, 
						    { text: app.localize('Delete'), visible: function () { return _permissions.delete; }, action: function (data) { deleteAddressEMailType(data.record.addressEMailType); } }
                        ]
                    }
                },
					{ targets: 1, data: "addressEMailType.uid", name: "uid", visible: false }, 
                    { targets: 2, data: "addressEMailType.name", name: "name" },
					{ targets: 3, data: "addressEMailType.code", name: "code" },
					{ targets: 4, data: "addressEMailType.order", name: "order" },
					{ targets: 5, data: "addressEMailType.status", name: "status" }
            ]
        });

In the following code (part of the GetAll function), the input.Sorting variable contains "name asc" with no mention of the Code field. I had expected to see "name asc, code desc" in that variable.

                var pagedAndFilteredAddressEMailTypes = filteredAddressEMailTypes
                    .OrderBy(input.Sorting ?? "id asc")
                    .PageBy(input);

Because the sort arrow indicators are behaving correctly, I assume that multiple column sorting is already turned on and supported. What am I missing? Do I need to manually capture the sort information from the table and then override the "sorting" member on the listAction.inputFilter?

Question

Now that I have completed the first release version of my AspNetZero project, I want to go back and put all of my user guides into an online website. I have looked at the Abp Docs Module and I believe it will serve my need very well, but I am a little bit fuzzy on how to integrate the Docs module with AspNetZero.

Here are may goals:

  1. add a Docs module to my AspNetZero project
  2. my project consists of mutliple products which are identified by name (a product), version (software release version) , and edition (abp edition).
  3. user login accounts on the main product must drive that user's access to appropriate documentation.
  4. I use Mercurial for revision control and would prefer not to have to move to GIT.

My questions:

  1. Is there a guide somewhere that explains how to add the Docs module to an AspNetZero project?
  2. Looking at Abp Docs Module,
    1. Step 1 - Download
      1. it seemed like maybe this step has already been satisfied by using the AspNetZero project; that this step 1 should be skipped.
    2. Step 2 - Referencing Docs Module Packages
      1. The choice to manually install the nuget packages felt like the most likely path to success. However, the AspNetZero project does not contain a project that I could identify as equivalent to "Acme.MyProject.Domain". The others (EntityFrameworkCore, Application, and Web) are all obvious...but the Domain appears to be missing. Do I need to add it? And what is the best way to do that to assure the projects are properly linked?
    3. Step 3 - Adding Module Dependencies
      1. Adding the DependsOn statements seems pretty straightforward. However, none of the AspNetZero module extension classes match the example "MyProject...." classes in the Abp Docs examples. Some clarification might be helpful.
    4. Step 4 - Database Integration
      1. Again, this seems fairly straight forward, but the Abp examples differ slightly from the AspNetZero code. Clarification would be helpful.
      2. In the Abp example code, it seemslike the addition of "builder.ConfigureDocs();" is the only required additional code....and I assume that can be added just after the "base.OnModelCreating(modelBuilder);" that appears in theOnModelCreating function of the AspNetZero ProjectNameDbContext class.
      3. adding of the migration and updating the database are straight forward and are expected to work as described.
    5. Step 5 - Linking Docs Module
      1. The "ConfigureMainMenuAsync" function does not exist in the AspNetZero project.
      2. It appears as though perhaps the new menu item should be added in the SetNavigation function of AppNavigationProvider.cs
        1. after the code shown below in Code Sample 1, add something like the code shown below in Code Sample 2.
    6. Step 6 - Adding New Docs Project
      1. No questions about this particular step.
    7. Step 7 - Creating a New Document
      1. No questions about this particular step.
    8. Step 8 - Creating the Navigation Document
      1. No questions about this particular step.
  3. What is the mechanism for integrating user-authentication to assure that some documents are only visible to users who have sufficient feature/permission credentials?

Code Sample 1

public override void SetNavigation(INavigationProviderContext context)
        {
            var menu = context.Manager.Menus[MenuName] = new MenuDefinition(MenuName, new FixedLocalizableString("Main Menu"));

Code Sample 2

                menu.AddItem(new MenuItemDefinition(
                        AppPageNames.Host.Documents,
                        L("Documents"),
                        url: "Documents",
                        icon: "flaticon-more",
                        permissionDependency: new SimplePermissionDependency(AppPermissions.Pages_Administration_Host_Documents)
                    )
                );

What is the proper way to publish a notification from a tenant user event to the host? Any host user that subscribes to the notification should receive it.

Using a null in the tenantIds array causes AbpBackgroundJobs to fail when attempting to process the AbpNotifications table.

await _notificationPublisher.PublishAsync(
    notificationName,
    notification,
    severity: NotificationSeverity.Info,
    tenantIds: new int?[] { null }
);

While we are at it...can someone explain the logic to me for use of the EntityId, EntityTypeAssemblyQualifiedName, & EntityTypeName fields in the AbpNotificationSubscription table? It seems as though an exact match between these fields and the notification EntittyIdentifier parameter will allow the notification to occur. But if the notification EntityIdentifier parameter is specified and the subscription specifies nulls across those fields, then the match does not happen and no notification is distributed.

From my perspective, the logic should be this...(but please correct me where I'm wrong).

The publisher provides as much information as is available and allows the subscriber to decide what information is desired. If the notification is unrelated to a specific object, then those Entity-related fields do not get populated.  But if the notification is related to a specific object, then those fields will be populated.  The subscriber (with the help of UI controls) uses the chart below to decide the level of information used to filter the notifications. <br> | No. | EntityId | EntityTypeAssemblyQualifiedName | EntityTypeName | NotificationName | Result | | --- | -------- | ------------------------------- | -------------- | ---------------- | ------ | | 1 | null | null | null | set | Receive any notification of the specified name, even if EntityIdentifier parameter has been specified. | | 2 | null | null | set | set | Receive any notification of the specified name, but only when EntityTypeName matches the EntityIdentifier parameter of the notification. Theoretically, the same class name could be loaded from different assemblies and all would apply.   For example: System.Reports and Custom.Reports assemblies could each have implementations of CommonReportNotifier.  Perhaps not likely...but possible. | | 3 | set | null | set | set | Same as #2 above, but in this case, the entityId must match the specific record. This is the best scenario to use for placing a "watch" on an object to monitor changes. | | 4 | null | set | set/null | set | Same as #2, but in this case, notifications would be distributed only for a specific assembly. | | 5 | set | set | set/null | set | Fully-qualified match.  The user would receive notifications only for a very specific object instance of a specific type in a specific assembly. |

AspNetZero 7.2.0 MVC Core jQuery. Where is the best place to put code that will execute just once during user login?

AspNetZero v7.2, MVC, jQuery

Often (but not always), the username is not recorded in the AuditLog during login. It seems to work reliably during logout. Also, it does not appear to record the tenant in either case. I have looked, but can not see in the code where the AuditLog is being written. I have also tried to force a few SaveChanges() on the current UnitOfWorkManager in various places to see if I could figure out if the log is being written by ABP dlls; but I was unsuccessful. Where is this happening? How can I add more information to the AuditLog record before it is written?

Showing 1 to 10 of 18 entries