I ended up getting it to work, but I now want to Implement a GenericAppService. But its throwing this error:
Castle.MicroKernel.Handlers.HandlerException occurred HResult=0x80131500 Message=Can't create component 'MMC.Platform.Web.Areas.App.Controllers.RPIListenerQueueController' as it has dependencies to be satisfied.
'MMC.Platform.Web.Areas.App.Controllers.RPIListenerQueueController' is waiting for the following dependencies:
- Service 'MMC.Platform.Generic.GenericAppService`3[[MMC.Platform.DMPModels.RpilistenerQueue, MMC.Platform.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null],[MMC.Platform.DMPModels.RpilistenerQueue, MMC.Platform.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null],[System.Int16, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' which was not registered.
Source=
public class
GenericAppService<TEntity, TEntityDTO, TPrimaryKeyType> :
AsyncCrudAppService<TEntity, TEntityDTO, TPrimaryKeyType, TEntityDTO, TEntityDTO, TEntityDTO, TEntityDTO,
TEntityDTO>, IGenericAppService<TEntityDTO, TPrimaryKeyType>
where TEntity : class, IEntity<TPrimaryKeyType> where TEntityDTO : IEntityDto<TPrimaryKeyType>
{
public GenericAppService(IRepository<TEntity, TPrimaryKeyType> repository) : base(repository)
{
}
public IQueryable GetAllQueryable()
{
return Repository.GetAll();
}
}
public interface IGenericAppService<TEntity, TPrimaryKeyType> : IAsyncCrudAppService<TEntity, TPrimaryKeyType,
TEntity, TEntity, TEntity, TEntity, TEntity> where TEntity : IEntityDto<TPrimaryKeyType>
{
IQueryable GetAllQueryable();
}
public abstract class TelerikCRUDPlatformControllerBase<TEntity, TEntityDTO, TPrimaryKeyType> : PlatformControllerBase
where TEntity : AuditBase<TPrimaryKeyType> where TEntityDTO : IEntityDto<TPrimaryKeyType>
{
private readonly GenericAppService<TEntity, TEntityDTO, TPrimaryKeyType> _appService;
private string _deletePermission;
private string _createPermission;
private string _editPermission;
private string _readPermission;
protected TelerikCRUDPlatformControllerBase(GenericAppService<TEntity, TEntityDTO, TPrimaryKeyType> appService)
{
_appService = appService;
}
public virtual ActionResult Index()
{
return View();
}
public virtual JsonResult Read([DataSourceRequest] DataSourceRequest request)
{
if (!PermissionChecker.IsGranted(_readPermission))
{
throw new AbpAuthorizationException("You are not authorized to view/read!"); //ToDo: Create Localization
}
return Json(_appService.GetAllQueryable().ToDataSourceResult(request));
}
[HttpPost]
[DontWrapResult]
public virtual async Task<ActionResult> Create([DataSourceRequest] DataSourceRequest request, TEntityDTO entity)
{
if (!PermissionChecker.IsGranted(_createPermission))
{
throw new AbpAuthorizationException("You are not authorized to create!"); //ToDo: Create Localization
}
if (ModelState.IsValidWithNoAuditFieldsSet())
await _appService.Create(entity);
return Json(new[] {entity}.ToDataSourceResult(request, ModelState));
}
[HttpPost]
[DontWrapResult]
public virtual async Task<ActionResult> Update([DataSourceRequest] DataSourceRequest request, TEntityDTO entity)
{
if (!PermissionChecker.IsGranted(_editPermission))
{
throw new AbpAuthorizationException("You are not authorized to edit!"); //ToDo: Create Localization
}
if (ModelState.IsValidWithNoAuditFieldsSet())
await _appService.Update(entity);
return Json(new[] {entity}.ToDataSourceResult(request, ModelState));
}
[HttpPost]
[DontWrapResult]
public virtual async Task<ActionResult> Destroy([DataSourceRequest] DataSourceRequest request, TEntityDTO entity)
{
if (!PermissionChecker.IsGranted(_deletePermission))
{
throw new AbpAuthorizationException("You are not authorized to delete!"); //ToDo: Create Localization
}
await _appService.Delete(entity);
return Json(new[] {entity}.ToDataSourceResult(request, ModelState));
}
[HttpPost]
public ActionResult Telerik_Export(string contentType, string base64, string fileName)
{
var fileContents = Convert.FromBase64String(base64);
return File(fileContents, contentType, fileName);
}
}
Controller works if I make a normal AppService and derive from the CrudAsync
public class RPIListenerQueueController : TelerikCRUDPlatformControllerBase<RpilistenerQueue, RpilistenerQueue, short>
{
//private IRPIListenerQueueAppService _appService;
private string _deletePermission;
private string _createPermission;
private string _editPermission;
private string _readPermission;
//public RPIListenerQueueController(IRPIListenerQueueAppService appService)
//{
// _appService = appService;
//}
//public virtual ActionResult Index()
//{
// return View();
//}
//public virtual JsonResult Read([DataSourceRequest] DataSourceRequest request)
//{
// if (!PermissionChecker.IsGranted(_readPermission))
// {
// throw new AbpAuthorizationException("You are not authorized to view/read!"); //ToDo: Create Localization
// }
// return Json(_appService.GetAllQueryable().ToDataSourceResult(request));
//}
//[HttpPost]
//[DontWrapResult]
//public virtual async Task<ActionResult> Create([DataSourceRequest] DataSourceRequest request, RpilistenerQueue entity)
//{
// if (!PermissionChecker.IsGranted(_createPermission))
// {
// throw new AbpAuthorizationException("You are not authorized to create!"); //ToDo: Create Localization
// }
// if (ModelState.IsValidWithNoAuditFieldsSet())
// await _appService.Create(entity);
// return Json(new[] { entity }.ToDataSourceResult(request, ModelState));
//}
//[HttpPost]
//[DontWrapResult]
//public virtual async Task<ActionResult> Update([DataSourceRequest] DataSourceRequest request, RpilistenerQueue entity)
//{
// if (!PermissionChecker.IsGranted(_editPermission))
// {
// throw new AbpAuthorizationException("You are not authorized to edit!"); //ToDo: Create Localization
// }
// if (ModelState.IsValidWithNoAuditFieldsSet())
// await _appService.Update(entity);
// return Json(new[] { entity }.ToDataSourceResult(request, ModelState));
//}
//[HttpPost]
//[DontWrapResult]
//public virtual async Task<ActionResult> Destroy([DataSourceRequest] DataSourceRequest request, RpilistenerQueue entity)
//{
// if (!PermissionChecker.IsGranted(_deletePermission))
// {
// throw new AbpAuthorizationException("You are not authorized to delete!"); //ToDo: Create Localization
// }
// await _appService.Delete(entity);
// return Json(new[] { entity }.ToDataSourceResult(request, ModelState));
//}
//[HttpPost]
//public ActionResult Telerik_Export(string contentType, string base64, string fileName)
//{
// var fileContents = Convert.FromBase64String(base64);
// return File(fileContents, contentType, fileName);
//}
public RPIListenerQueueController(GenericAppService<RpilistenerQueue, RpilistenerQueue, short> appService) : base(appService)
{
}
}
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?
NM, by me adding it to the bundleconfig and right clicking minifiy it was adding it again and messing something up.
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"
]
},
Yeah, if use the javascript method it give me the filter is null error.
Heres the MVC Core version that I got working.... Finally after I realized they changed the default serializer to camelCase lol
@(Html.Kendo().Grid<UserListDto>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.Name);
columns.Bound(p => p.Surname);
columns.Bound(p => p.IsActive);
})
//.ToolBar(toolbar => {
// toolbar.Create();
// toolbar.Save();
//})
//.Editable(editable => editable.Mode(GridEditMode.InCell))
.Pageable()
.Mobile(MobileMode.Auto)
.Navigatable()
.Sortable()
.Scrollable()
.Filterable()
.ColumnMenu()
.DataSource(dataSource => dataSource
.Custom()
.PageSize(20)
.Schema(schema => schema.Data("result.items").Total("result.totalCount").Errors("result.error")
.Model(m =>
{
m.Id(x => x.Id);
m.Field(x => x.Name).From("name");
m.Field(x => x.Surname).From("surname");
m.Field(x => x.IsActive).From("isActive");
}))
.Transport(transport =>
{
transport.Read(read =>
read.Url("http://localhost:62114/api/services/app/User/GetUsers")
);
})
))
Heres a more enhanced version
@using MMC.Platform.Authorization.Users.Dto
@{
ViewData["Title"] = "View";
}
@(Html.Kendo().Grid<UserListDto>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.UserName).Title(@L("UserName"));
columns.Bound(p => p.Name).Title(@L("Name"));
columns.Bound(p => p.Surname).Title(@L("Name"));
columns.Bound(p => p.Roles).Title(@L("Roles")).ClientTemplate("#= getRoleNames(Roles)#");
columns.Bound(p => p.EmailAddress).Title(@L("EmailAddress"));
columns.Bound(p => p.IsEmailConfirmed).Title(@L("EmailConfirm"))
.ClientTemplate("#if(IsEmailConfirmed) {# <span class='label label-success'> #= app.localize('Yes') # </span>#} else {# <span class='label label-default'> #= app.localize('No') # </span>#}#")
.Filterable(filterable => filterable.Messages(m => m.IsFalse(@L("No"))).Messages(m => m.IsTrue(@L("Yes"))));
columns.Bound(p => p.IsActive).Title(@L("Active"))
.ClientTemplate("#if(IsActive) {# <span class='label label-success'> #= app.localize('Yes') # </span>#} else {# <span class='label label-default'> #= app.localize('No') # </span>#}#")
.Filterable(filterable =>filterable.Messages(m=>m.IsFalse(@L("No"))).Messages(m=>m.IsTrue(@L("Yes"))));
columns.Bound(p => p.LastLoginTime).Title(@L("LastLoginTime")).ClientTemplate("#= moment(LastLoginTime).format('L')#");
columns.Bound(p => p.CreationTime).Title(@L("CreationTime")).ClientTemplate("#= moment(CreationTime).format('L')#");
})
//.ToolBar(toolbar => {
// toolbar.Create();
// toolbar.Save();
//})
//.Editable(editable => editable.Mode(GridEditMode.InCell))
.Pageable()
.Mobile(MobileMode.Auto)
.Navigatable()
.Sortable()
.Scrollable()
.Filterable()
.ColumnMenu()
.DataSource(dataSource => dataSource
.Custom()
.PageSize(20)
.Schema(schema => schema.Data("result.items").Total("result.totalCount").Errors("result.error")
.Model(m =>
{
m.Id(x => x.Id);
m.Field(x => x.Name).From("name");
m.Field(x => x.Surname).From("surname");
m.Field(x => x.UserName).From("userName");
m.Field(x => x.Roles).From("roles");
m.Field(x => x.EmailAddress).From("emailAddress");
m.Field(x => x.IsEmailConfirmed).From("isEmailConfirmed");
m.Field(x => x.IsActive).From("isActive");
m.Field(x => x.LastLoginTime).From("lastLoginTime");
m.Field(x => x.CreationTime).From("creationTime");
}))
.Transport(transport =>
{
transport.Read(read =>
read.Url("http://localhost:62114/api/services/app/User/GetUsers")
);
})
))
<script>
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;
}
</script>
Can you also make an example using the MVC helpers. The intellisense is way better when trying to remember all of Teleriks toggles :)
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>
Thanks, that was it.
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();
}
}