Hi There
I am using the regular EF version not core. I have got the following entities.
[Table("BusinessUnits")]
public class BusinessUnit : FullAuditedEntity
{
[Required]
public string Name { get; set; }
[Required]
public string SharepointMapping { get; set; }
}
[Table("Brands")]
public class Brand : FullAuditedEntity
{
[Required]
public string Name { get; set; }
[Required]
public string SharepointMapping { get; set; }
[ForeignKey("BusinesUnitId")]
public virtual BusinessUnit BusinessUnit { get; set; }
public virtual int BusinesUnitId { get; set; }
}
[Table("Products")]
public class Product : FullAuditedEntity
{
[Required]
public string Name { get; set; }
[Required]
public string SharepointMapping { get; set; }
[ForeignKey("BrandId")]
public virtual Brand Brand { get; set; }
public virtual int BrandId { get; set; }
}
The navigation properties - lazy loading works for the first two entities but when I try list the Products Entity from a webservice call I get the following error.
{"message":"An error has occurred.","exceptionMessage":"The 'ObjectContent1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","exceptionType":"System.InvalidOperationException","stackTrace":null,"innerException":{"message":"An error has occurred.","exceptionMessage":"Error getting value from 'BusinessUnit' on 'System.Data.Entity.DynamicProxies.Brand_486DF76111C074CB5B97521E6C0339967681A92DC158A5A4CBD2B5E9A75D0277'.","exceptionType":"Newtonsoft.Json.JsonSerializationException","stackTrace":" at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.","exceptionType":"System.ObjectDisposedException","stackTrace":" at System.Data.Entity.Core.Objects.ObjectContext.get_Connection()\r\n at System.Data.Entity.Core.Objects.ObjectQuery
1.GetResults(Nullable1 forMergeOption)\r\n at System.Data.Entity.Core.Objects.ObjectQuery
1.Execute(MergeOption mergeOption)\r\n at System.Data.Entity.Core.Objects.DataClasses.EntityReference1.Load(MergeOption mergeOption)\r\n at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.DeferredLoad()\r\n at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.LoadProperty[TItem](TItem propertyValue, String relationshipName, String targetRoleName, Boolean mustBeNull, Object wrapperObject)\r\n at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.<>c__DisplayClass7
2.<GetInterceptorDelegate>b__2(TProxy proxy, TItem item)\r\n at System.Data.Entity.DynamicProxies.Brand_486DF76111C074CB5B97521E6C0339967681A92DC158A5A4CBD2B5E9A75D0277.get_BusinessUnit()\r\n at GetBusinessUnit(Object )\r\n at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"}}}
Here is the service that is being used for the lookup.
var products = _productRepository.GetAll().ToList();
Is there an issue with getting entities 3 levels deep.
Thanks
FYI Fixed with a little hack returning the parent as a string
public ListResultDto<CategoryListDto>GetCategories()
{
var categories = _categoryRepository.GetAll().ToList()
.Select(r => new CategoryListDto
{
Id = r.Id,
Name = r.Name,
SharepointMapping = r.SharepointMapping,
Parent = GetCategoryName(r.ParentId)
});
return new ListResultDto<CategoryListDto>(categories.MapTo<List<CategoryListDto>>()); ;
}
Hi All Thanks for all the help. I think I have got to the bottom of the issue.
I changed the following code to use default verbs.
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder
.ForAll<IApplicationService>(typeof(BabcockCRMApplicationModule).Assembly, "app")
.WithConventionalVerbs()
.Build();
So now it will use a get and not post.
When I ran the code I got the following error.
"message":"An error has occurred.","exceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","exceptionType":"System.InvalidOperationException","stackTrace":null,"innerException":{"message":"An error has occurred.","exceptionMessage":"Self referencing loop detected for property 'parent' with type 'Clarity.BabcockCRM.Models.Category'
So in my opinion this is the error that was causing the issue in the first place. Is there any way to solve this?
Hi There
I removed all parameters. I am retrieving all records so dont need any parameters for now. So the GetCategories class doesnt accept any parameters any more and it still does a get.
Same error.
The funny thing is it only returns the error when there is a record with a ParentId ie the Parent Property is not null. Else the call works fine.
Should I decorate the service with httppost annotation.
Full controller
namespace Clarity.BabcockCRM.Web.Areas.Mpa.Controllers
{
[AbpMvcAuthorize(AppPermissions.Pages_Administration_Categories)]
public class CategoriesController : BabcockCRMControllerBase
{
private readonly ICategoryAppService _categoryAppService;
public CategoriesController(ICategoryAppService categoryAppService)
{
_categoryAppService = categoryAppService;
}
public ActionResult Index(GetCategoriesInput input)
{
var output = _categoryAppService.GetCategories(input);
var model = new IndexViewModel(output);
return View(model);
}
public async Task<PartialViewResult> CreateOrEditModal(int? id)
{
var output = await _categoryAppService.GetCategoryForEdit(new NullableIdDto { Id = id });
var viewModel = new CreateOrEditCategoryModalViewModel(output);
return PartialView("_CreateOrEditModal", viewModel);
}
}
}
Full Category App Service. The Javascript calls the app service directly
[AbpAuthorize(AppPermissions.Pages_Administration_Categories)]
public class CategoryAppService : BabcockCRMServiceBase, ICategoryAppService
{
private readonly IRepository<Category> _categoryRepository;
public CategoryAppService(IRepository<Category> categoryRepository)
{
_categoryRepository = categoryRepository;
}
public ListResultDto<CategoryListDto> GetCategories(GetCategoriesInput input)
{
var categories = _categoryRepository
.GetAll()
.WhereIf(
!input.Filter.IsNullOrEmpty(),
p => p.Name.Contains(input.Filter)
)
.OrderBy(p => p.Name)
.ToList();
return new ListResultDto<CategoryListDto>(categories.MapTo<List<CategoryListDto>>());
}
public async Task CreateOrUpdateCategory(CreateOrUpdateCategoryInput input)
{
if (input.Category.Id.HasValue)
{
await UpdateCategoryAsync(input);
}
else
{
await CreateCategoryAsync(input);
}
}
protected virtual async Task UpdateCategoryAsync(CreateOrUpdateCategoryInput input)
{
Debug.Assert(input.Category.Id != null, "input.Category.Id should be set.");
var category = await _categoryRepository.GetAsync(input.Category.Id.Value);
category.Name = input.Category.Name;
category.SharepointMapping = input.Category.SharepointMapping;
category.ParentId = input.Category.ParentId;
await _categoryRepository.UpdateAsync(category);
}
protected virtual async Task CreateCategoryAsync(CreateOrUpdateCategoryInput input)
{
var category = new Category()
{ Name = input.Category.Name,
SharepointMapping = input.Category.SharepointMapping,
ParentId = input.Category.ParentId};
await _categoryRepository.InsertAsync(category);
await CurrentUnitOfWork.SaveChangesAsync(); //It's done to get Id of the role.
}
public async Task CreateCategory(CreateCategoryInput input)
{
var category = input.MapTo<Category>();
await _categoryRepository.InsertAsync(category);
}
public async Task<GetCategoryForEditOutput> GetCategoryForEdit(NullableIdDto input)
{
var categorylist = _categoryRepository.GetAll().ToList();
CategoryEditDto categoryEditDto;
if (input.Id.HasValue) //Editing existing role?
{
var category = await _categoryRepository.GetAsync(input.Id.Value);
categoryEditDto = category.MapTo<CategoryEditDto>();
}
else
{
categoryEditDto = new CategoryEditDto();
}
return new GetCategoryForEditOutput
{
Category = categoryEditDto,
CategoryList = categorylist.MapTo<List<Category>>().OrderBy(p => p.Name).ToList(),
};
}
public async Task DeleteCategory(EntityDto input)
{
var category = await _categoryRepository.GetAsync(input.Id);
await _categoryRepository.DeleteAsync(category);
}
}
Hi There
Please find controller code below. Still getting issues after forcing javascript to force null values.
public ActionResult Index(GetCategoriesInput input)
{
var output = _categoryAppService.GetCategories(input);
var model = new IndexViewModel(output);
return View(model);
}
Thanks for the reply thats what I thought.
I have not created any custom API for this.
Its being called by jTable in javascript.
_$categoriesTable.jtable({
title: app.localize('Categories'),
actions: {
listAction: {
method: _categoryService.getCategories
}
},
I removed all the records with ParentIds and did not get this error. When I added a parentId to one of them I got the error again.
Not sure what is happening
Could it be an issue with jtable when the navigation property is null.
Category.Parent = null
So then category.parent.name will throw an exception error
My controller and AppService returns data correctly.
Here is full javascript
(function () {
$(function () {
var _$categoriesTable = $('#CategoriesTable');
var _categoryService = abp.services.app.category;
var _permissions = {
create: abp.auth.hasPermission('Pages.Administration.Categories'),
edit: abp.auth.hasPermission('Pages.Administration.Categories'),
'delete': abp.auth.hasPermission('Pages.Administration.Categories')
};
var _createOrEditModal = new app.ModalManager({
viewUrl: abp.appPath + 'Mpa/Categories/CreateOrEditModal',
scriptUrl: abp.appPath + 'Areas/Mpa/Views/Categories/_CreateOrEditModal.js',
modalClass: 'CreateOrEditCategoryModal'
});
_$categoriesTable.jtable({
title: app.localize('Categories'),
actions: {
listAction: {
method: _categoryService.getCategories
}
},
fields: {
id: {
key: true,
list: false
},
actions: {
type: 'record-actions',
cssClass: 'btn btn-xs btn-primary blue',
text: '<i class="fa fa-cog"></i> ' + app.localize('Actions') + ' <span class="caret"></span>',
items: [{
text: app.localize('Edit'),
visible: function () {
return _permissions.edit;
},
action: function (data) {
_createOrEditModal.open({ id: data.record.id });
}
}, {
text: app.localize('Delete'),
visible: function (data) {
return !data.record.isStatic && _permissions.delete;
},
action: function (data) {
deleteRole(data.record);
}
}]
},
Name: {
title: app.localize('CategoryName'),
width: '35%',
display: function (data) {
var $span = $('<span></span>');
$span.append(data.record.name + " ");
return $span;
}
},
SharePointMapping: {
title: app.localize('SharePointName'),
width: '35%',
display: function (data) {
var $span = $('<span></span>');
$span.append(data.record.sharepointMapping + " ");
return $span;
}
},
ParentName: {
title: app.localize('ParentName'),
width: '35%',
display: function (data) {
var $span = $('<span></span>');
$span.append(data.record.parent + " ");
return $span;
}
},
}
});
function deleteRole(role) {
abp.message.confirm(
app.localize('RoleDeleteWarningMessage', role.displayName),
function (isConfirmed) {
if (isConfirmed) {
_roleService.deleteRole({
id: role.id
}).done(function () {
getRoles();
abp.notify.success(app.localize('SuccessfullyDeleted'));
});
}
}
);
};
$('#CreateNewCategoryButton').click(function () {
_createOrEditModal.open();
});
$('#RefreshCategoriesButton').click(function (e) {
e.preventDefault();
getCategories();
});
function getCategories() {
_$categoriesTable.jtable('load');
}
abp.event.on('app.createOrEditRoleModalSaved', function () {
getCategories();
});
getCategories();
});
})();
Hi There
This may be a very noob question but I am struggling to implement a standard @Html.DropDownListFor. Does anybody have ant examples or can show me how to implement this.
Modal Code
<label for="ParentId">@L("Parent Category")</label>
@Html.DropDownList("ParentId", Model.CategoryList.Select(i => i.ToSelectListItem()), new { @class = "form-control edited" })
Controller
public async Task<PartialViewResult> CreateOrEditModal(int? id)
{
var output = await _categoryAppService.GetCategoryForEdit(new NullableIdDto { Id = id });
var viewModel = new CreateOrEditCategoryModalViewModel(output);
return PartialView("_CreateOrEditModal", viewModel);
}
APP Service
public async Task<GetCategoryForEditOutput> GetCategoryForEdit(NullableIdDto input)
{
var categorylist = _categoryRepository.GetAll().ToList();
CategoryEditDto categoryEditDto;
if (input.Id.HasValue) //Editing existing role?
{
var category = await _categoryRepository.GetAsync(input.Id.Value);
categoryEditDto = category.MapTo<CategoryEditDto>();
}
else
{
categoryEditDto = new CategoryEditDto();
}
return new GetCategoryForEditOutput
{
Category = categoryEditDto,
CategoryList = categorylist.
};
}
DTO
public class GetCategoryForEditOutput
{
public CategoryEditDto Category { get; set; }
public List<ComboboxItemDto> CategoryList { get; set; }
}
I am getting the following error when query a recursive entity lookup.
{"message":"An error has occurred.","exceptionMessage":"There is an action GetCategories defined for api controller app/category but with a different HTTP Verb. Request verb is GET. It should be Post","exceptionType":"System.Web.HttpException","stackTrace":" at Abp.WebApi.Controllers.Dynamic.Selectors.AbpApiControllerActionSelector.GetActionDescriptorByActionName(HttpControllerContext controllerContext, DynamicApiControllerInfo controllerInfo, String actionName)\r\n at Abp.WebApi.Controllers.Dynamic.Selectors.AbpApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n at Castle.Proxies.DynamicApiController1Proxy_5.ExecuteAsync_callback(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n at Castle.Proxies.Invocations.ApiController_ExecuteAsync_5.InvokeMethodOnTarget()\r\n at Castle.DynamicProxy.AbstractInvocation.Proceed()\r\n at Abp.WebApi.Controllers.Dynamic.Interceptors.AbpDynamicApiControllerInterceptor1.Intercept(IInvocation invocation)\r\n at Castle.DynamicProxy.AbstractInvocation.Proceed()\r\n at Castle.Proxies.DynamicApiController`1Proxy_5.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"}
The error only occurs after I added the first entry that has a ParentId
Model
[Table("Categories")]
public class Category : FullAuditedEntity
{
[Required]
public string Name { get; set; }
[Required]
public string SharepointMapping { get; set; }
public int? ParentId { get; set; }
public Category Parent { get; set; }
public List<Category> Children { get; set; }
}
CategoryAppService
public ListResultDto<CategoryListDto> GetCategories(GetCategoriesInput input)
{
var categories = _categoryRepository
.GetAll()
.WhereIf(
!input.Filter.IsNullOrEmpty(),
p => p.Name.Contains(input.Filter)
)
.OrderBy(p => p.Name)
.ToList();
return new ListResultDto<CategoryListDto>(categories.MapTo<List<CategoryListDto>>());
}
CategoryListDto
[AutoMapFrom(typeof(Category))]
public class CategoryListDto : FullAuditedEntityDto
{
public string Name { get; set; }
public string SharepointMapping { get; set; }
public int? ParentId { get; set; }
public virtual Category Parent { get; set; }
}
Thanks I am pulling my hair out on this one