Base solution for your next web application

Activities of "bbakermmc"

How do I have my app service use my new db context? It looks like it wants an IRepository which points to the "default" context. Do I need to make a new AsyncCRUDServiceMyCustomDBContext and override the IRepository in there with my new one?

What is the preferred way to do bundling/minification of JS files.

I'm trying to follow your structure for the .js files but you guide doesn't say what to do.

I take this .js file and right click on it to bundle/minify and doesn't minify it.

var _userService = abp.services.app.user;

        var _permissions = {
            create: abp.auth.hasPermission("Administration.Users.Create"),
            edit: abp.auth.hasPermission("Administration.Users.Edit"),
            changePermissions: abp.auth.hasPermission("Administration.Users.ChangePermissions"),
            impersonation: abp.auth.hasPermission("Administration.Users.Impersonation"),
            'delete': abp.auth.hasPermission("Administration.Users.Delete")
        };

        var _createOrEditModal = new app.ModalManager({
            viewUrl: abp.appPath + "App/Users/CreateOrEditModal",
            scriptUrl: abp.appPath + "view-resources/Areas/App/Views/Users/_CreateOrEditModal.js",
            modalClass: "CreateOrEditUserModal"
        });

        var _userPermissionsModal = new app.ModalManager({
            viewUrl: abp.appPath + "App/Users/PermissionsModal",
            scriptUrl: abp.appPath + "view-resources/Areas/App/Views/Users/_PermissionsModal.js",
            modalClass: "UserPermissionsModal"
        });

        function permissions(e) {
            var dataItem = this.dataItem($(e.currentTarget).closest("tr"));

            _userPermissionsModal.open({ id: dataItem.Id });
        }

        function remove(e) {
            var dataItem = this.dataItem($(e.currentTarget).closest("tr"));

            deleteUser(dataItem);
        }

        function signIn(e) {
            abp.ui.setBusy();
            var dataItem = this.dataItem($(e.currentTarget).closest("tr"));

            abp.ajax({
                url: abp.appPath + "Account/Impersonate",
                data: JSON.stringify({
                    tenantId: abp.session.tenantId,
                    userId: dataItem.Id
                })
            }).fail(function () {
                abp.ui.clearBusy();
            });
        }

        function edit(e) {
            var dataItem = this.dataItem($(e.currentTarget).closest("tr"));

            _createOrEditModal.open({ id: dataItem.Id });
        }

        function unlock(e) {
            var dataItem = this.dataItem($(e.currentTarget).closest("tr"));

            _userService.unlockUser({
                id: dataItem.id
            }).done(function () {
                abp.notify.success(app.localize("UnlockedTheUser", dataItem.UserName));
            });
        }

        function dataBound(e) {
            var unlockSpan = "<span class='fa fa-unlock'></span>";
            e.sender.tbody.find(".k-grid-Unlock").prepend(unlockSpan);

            if (!_permissions.changePermissions) {
                e.sender.tbody.find(".k-grid-Unlock").remove();
            }

            var permissionSpan = "<span class='fa fa-key'></span>";
            e.sender.tbody.find(".k-grid-Permissions").prepend(permissionSpan);

            if (!_permissions.changePermissions) {
                e.sender.tbody.find(".k-grid-Permissions").remove();
            }

            var editSpan = "<span class='fa fa-edit'></span>";
            e.sender.tbody.find(".k-grid-Edit").prepend(editSpan);

            if (!_permissions.edit) {
                e.sender.tbody.find(".k-grid-Edit").remove();
            }

            var deleteSpan = "<span class='fa fa-remove'></span>";
            e.sender.tbody.find(".k-grid-Delete").prepend(deleteSpan);

            if (!_permissions["delete"]) {
                e.sender.tbody.find(".k-grid-Delete").remove();
            }

            var signInSpan = "<span class='fa fa-sign-in'></span>";
            e.sender.tbody.find(".k-grid-SignIn").prepend(signInSpan);

            if (!_permissions.impersonation) {
                e.sender.tbody.find(".k-grid-SignIn").remove();
            }

            var grid = $("#grid").data("kendoGrid");
            var gridData = grid.dataSource.view();

            for (var i = 0; i < gridData.length; i++) {
                if (_permissions.impersonation && gridData[i].Id === abp.session.userId) {
                    var tr = grid.table.find("tr[data-uid='" + gridData[i].uid + "']");
                    tr.find(".k-grid-SignIn").remove();
                }
            }
        }

        function deleteUser(user) {
            if (user.UserName === app.consts.userManagement.defaultAdminUserName) {
                abp.message.warn(app.localize("{0}UserCannotBeDeleted", app.consts.userManagement.defaultAdminUserName));
                return;
            }

            abp.message.confirm(app.localize("UserDeleteWarningMessage", user.UserName), function (isConfirmed) {
                if (isConfirmed) {
                    _userService.deleteUser({
                        id: user.Id
                    }).done(function () {
                        abp.notify.success(app.localize("SuccessfullyDeleted"));
                    });
                }
            });
        }

        function getRoleNames(roles) {
            var roleNames = "";
            for (var j = 0; j < roles.length; j++) {
                if (roleNames.length) {
                    roleNames = roleNames + ", ";
                }

                roleNames = roleNames + roles[j].roleName;
            };

            return roleNames;
        }

        function PermissionSelectionComboOnChange() {
            $("#grid").data("kendoGrid").dataSource.read();
        }

        function getAdvancedParameters() {
            var grid = $("#grid").data("kendoGrid");
            var currentPageSize = grid.dataSource.pageSize();
            var currentPage = grid.dataSource.page();

            var skipCount = 0;
            if (currentPage > 1) {
                skipCount = currentPageSize * currentPage - 1;
            }
            return {
                permission: $("#PermissionSelectionCombo").val(),
                role: $("#RoleSelectionCombo").val(),
                MaxResultCount: currentPageSize,
                SkipCount: skipCount
            };
        }

        function RoleSelectionComboboxOnChange() {
            $("#grid").data("kendoGrid").dataSource.read();
        }

        $("#grid").on("click", ".k-grid-createBtn", function () {
            _createOrEditModal.open();
        });

        $("#ShowAdvancedFiltersSpan").click(function () {
            $("#ShowAdvancedFiltersSpan").hide();
            $("#HideAdvancedFiltersSpan").show();
            $("#AdvacedAuditFiltersArea").slideDown();
        });

        $("#HideAdvancedFiltersSpan").click(function () {
            $("#HideAdvancedFiltersSpan").hide();
            $("#ShowAdvancedFiltersSpan").show();
            $("#AdvacedAuditFiltersArea").slideUp();
        });

But if I compile it, it then makes a .es5.js file and a .es5.min.js file then in my bundleconfig I can min the .es5.js file and it works fine. But if I don't compile it doesn't pick up changes.

{
        "outputFileName": "wwwroot/view-resources/Areas/App/Views/Users/indexTelerik.min.js",
        "inputFiles": [
            "wwwroot/view-resources/Areas/App/Views/Users/indexTelerik.es5.js"
        ]
    },

Following your example for the Kendo Grid integrations.

I get an error: Unable to get property 'filter' of undefined or null reference

/ action 'getUsers'
    abp.services.app.user.getUsers = function(input, ajaxParams) {
      return abp.ajax($.extend(true, {
        url: abp.appPath + 'api/services/app/User/GetUsers' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'permission', value: input.permission }, { name: 'role', value: input.role }, { name: 'sorting', value: input.sorting }, { name: 'maxResultCount', value: input.maxResultCount }, { name: 'skipCount', value: input.skipCount }]) + '',
        type: 'GET'
      }, ajaxParams));;
    };
<div>
    <h1>@L("Users")</h1>
    <div class="row buttons-area">
    </div>

    <div class="row">
        <div class="col-md-12">
            <div id="UsersGrid"></div>
        </div>
    </div>
</div>

<script>
    
 $(function () {

            $('#UsersGrid').kendoGrid({
                editable: true,
                filterable: false,
                columns: [{
                    field: 'userName',
                    title: 'UserName'
                }, {
                    field: 'name',
                    title: 'Name'
                }, {
                    field: 'surname',
                    title: 'Surname'
                }, {
                    field: 'emailAddress',
                    title: 'EmailAddress'
                }, {
                    field: 'isActive',
                    title: 'IsActive',
                    template: '#= isActive ? "YES" : "NO" #'
                }],
                dataSource: new kendo.data.DataSource({
                    autoSync: true,
                    transport: {
                        read: function(options) {
                            abp.services.app.user.getUsers()
                                .done(function (result) {
                                    options.success(result.items);
                                })
                                .fail(function(error) {
                                    options.error(error);
                                });
                        },
                        update: function(options) {
                            abp.services.app.user.updateUser(options.data)
                                .done(function(result) {
                                    options.success(null);
                                })
                                .fail(function(error) {
                                    options.error(error);
                                });
                        }
                    },
                    schema: {
                        model: {
                            id: 'id',
                            fields: {
                                id: {
                                    editable: false,
                                    nullable: true
                                },
                                userName: {
                                    editable: true
                                },
                                name: {
                                    editable: true
                                },
                                surname: {
                                    editable: true
                                },
                                emailAddress: {
                                    editable: true
                                },
                                isActive: {
                                    editable: false
                                }
                            }
                        }
                    }
                })
            });
        });


</script>

I have a custom repo which calls a stored proc and I get this error if I don't set the controller to [UnitOfWork(isTransactional: false)] I would much rather in the repo set the transaction to the same as the UoW or disable it in the repo/app service and not in the controller/anywhere I might call the method.

ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

public void ImportExternalAction(int contactId, string packageCode, string activityCode, string emailAddress,
        int sourceId, string user)
    {
        var cmd = Context.Database.GetDbConnection().CreateCommand();

        cmd.CommandText = "EXTERNAL_API@ImportExternalAction";
        cmd.CommandType = CommandType.StoredProcedure;

        cmd.Parameters.Add(new SqlParameter("i_ContactId", contactId));
        cmd.Parameters.Add(new SqlParameter("i_PackageCode", packageCode));
        cmd.Parameters.Add(new SqlParameter("i_EmailAddress", emailAddress));
        cmd.Parameters.Add(new SqlParameter("i_ActivityCode", activityCode));
        cmd.Parameters.Add(new SqlParameter("i_SourceId", sourceId));
        cmd.Parameters.Add(new SqlParameter("i_LoginName", user));

        var isOpen = cmd.Connection.State == ConnectionState.Open;
        if (!isOpen)
        {
            cmd.Connection.Open();
        }

        cmd.ExecuteNonQuery();

        if (isOpen)
        {
            cmd.Connection.Close();
        }

    }
Question

Is there a way to setup a unit test/appservice/change out the context to use a read DB instead of in memory?

Whats the preferred way to add existing tables that aren't managed via EF Migrations.
I need to add about 100 tables to use. The DBMs also set them up as TableNameId and not Id.

Can I just create another Context that uses the same connection string from the base Dbcontext?

Incase anyone is looking to filter the Swagger UI to prevent showing End Points for users who don't have permissions.

Note: In this case its checking for explicit permissions (Our use case). If you want it to show end points w/no permissions you will need to adjust it.

startup.cs

services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new Info { Title = "Platform API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.DocumentFilter<SwaggerAbpAuthorizeAttributeAuthorizationFilter>();
            });
new class file
public class SwaggerAbpAuthorizeAttributeAuthorizationFilter : IDocumentFilter
        {          
            private readonly IPermissionChecker _permissionChecker;

            public SwaggerAbpAuthorizeAttributeAuthorizationFilter( IPermissionChecker permissionChecker)
            {
                _permissionChecker = permissionChecker;
            }

            public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
            {
                var descriptions = context.ApiDescriptionsGroups.Items.SelectMany(group => group.Items);

                foreach (var description in descriptions)
                {
                  var authAttributes = description.ControllerAttributes()
                        .OfType<AbpAuthorizeAttribute>()
                        .Union(description.ActionAttributes()
                            .OfType<AbpAuthorizeAttribute>());

                    // check if this action should be visible
                    var forbiddenDuePermissions = IsForbiddenDuePermissions(authAttributes);

                    if (!forbiddenDuePermissions)
                        continue; // user passed all permissions checks

                    var route = "/" + description.RelativePath.TrimEnd('/');
                    var path = swaggerDoc.Paths[route];

                    // remove method or entire path (if there are no more methods in this path)
                    switch (description.HttpMethod)
                    {
                        case "DELETE":
                            path.Delete = null;
                            break;
                        case "GET":
                            path.Get = null;
                            break;
                        case "HEAD":
                            path.Head = null;
                            break;
                        case "OPTIONS":
                            path.Options = null;
                            break;
                        case "PATCH":
                            path.Patch = null;
                            break;
                        case "POST":
                            path.Post = null;
                            break;
                        case "PUT":
                            path.Put = null;
                            break;
                        default: throw new ArgumentOutOfRangeException("Method name not mapped to operation");
                    }

                    if (path.Delete == null && path.Get == null &&
                        path.Head == null && path.Options == null &&
                        path.Patch == null && path.Post == null && path.Put == null)
                        swaggerDoc.Paths.Remove(route);
                }
            }

            private bool IsForbiddenDuePermissions(IEnumerable<AbpAuthorizeAttribute> attributes)
            {
                var authorizeAttributes = attributes
                    .Where(p => p.Permissions != null).ToList();

                var permissions = new List<string>();
                if (authorizeAttributes.Count != 0)
                {
                    foreach (var authorizeAttribute in authorizeAttributes)
                    {
                        permissions.AddRange(authorizeAttribute.Permissions.ToList());
                    }
                }
                else
                {
                    return true;
                }

                foreach (var permission in permissions)
                {
                    var allow = _permissionChecker.IsGranted(permission);
                    if (allow)
                    {
                        return false;
                    }
                }

                return true;
            }
        }

We have a DLL that contains all of our DB logic for connecting to each of our clients DBs. Is there a way to register it so it can make the methods usable in JS like the APP/AppServices does?

I found this but I cant find a DynamicApiControllerBuilder in any of the code.

DynamicApiControllerBuilder
    .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem")
    .Build();
Question

I extended the Tenant entity and deployed the change to my DB/updated the created/edit forms.

How do I pull this extra info I need into my controller/Extend the ABPSession to put it there. The field is an API key that we need to use all the time for each client to hit our internal APIs.

How is everyone keeping up to date? Are you just using the project on github and then pulling the changes in? (Did you keep the same MyCompany.xxxx structure)?

Just trying to figure out the best way for us to start the project and if we should pull a copy of the github version into TFS and then go from there or pull the copy from the download site with the replaced names.

Showing 1 to 10 of 19 entries