Hi All, I have the same problem. Anyone solved the issue?
<cite>Shyamjith: </cite> I did wrote code here but i can't invoke it using Repository
What do you mean with this sentence? Do you mean you don't see methods from a client class of your repository? If so, it is a matter of interfaces.
Your concrete repository is probably declare in this way:
public class MySpecificRepo : SampleRepositoryBase<MyEntity, int>, IMySpecificRepo {
...
}
This means, clients see your class by the interface IMySpecificRepo.
So you have to define a ISampleRepositoryBase interface declaring the new methods added to SampleRepositoryBase and declare your Concrete Interface by extending it:
public interface ISampleRepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> {
// here your additional common methods declarations
...
}
public interface IMySpecificRepo : ISampleRepositoryBase<MyEntity, int> {
// here your specific repository methods
...
}
public class MySpecificRepo : SampleRepositoryBase<MyEntity, int>, IMySpecificRepo {
// here the implementations
...
}
In this way all works
Gp
<cite>hikalkan: </cite> this maybe related to that: <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1163">https://github.com/aspnetboilerplate/as ... ssues/1163</a> After v0.10 release, please try it again.
It is still there, but I went on with my investigation and I was able to get the exception thrown when running the code:
await UsingDbContextAsync(AbpSession.TenantId, async context => {
entity = await context.REProperties.OfType<PropertyForSale>()
.FirstAsync(u => (u.TenantId == AbpSession.TenantId));
});
I receive this error:
Result StackTrace:
at Effort.DbConnectionFactory.CreateTransient()
at MyNewHouse.Tests.MyNewHouseTestBase.UseSingleDatabase() in C:\WA\GpES\MyNewHouse\Tests\MyNewHouse.Tests\MyNewHouseTestBase.cs:line 68
at MyNewHouse.Tests.MyNewHouseTestBase.PreInitialize() in C:\WA\GpES\MyNewHouse\Tests\MyNewHouse.Tests\MyNewHouseTestBase.cs:line 60
at Abp.TestBase.AbpIntegratedTestBase`1.InitializeAbp() in D:\Halil\GitHub\aspnetboilerplate\src\Abp.TestBase\TestBase\AbpIntegratedTestBase.cs:line 42
at Abp.TestBase.AbpIntegratedTestBase`1..ctor(Boolean initializeAbp) in D:\Halil\GitHub\aspnetboilerplate\src\Abp.TestBase\TestBase\AbpIntegratedTestBase.cs:line 34
at Abp.TestBase.AbpIntegratedTestBase`1..ctor(Boolean initializeAbp) in D:\Halil\GitHub\aspnetboilerplate\src\Abp.TestBase\TestBase\AbpIntegratedTestBase.cs:line 34
at MyNewHouse.Tests.MyNewHouseTestBase..ctor() in C:\WA\GpES\MyNewHouse\Tests\MyNewHouse.Tests\MyNewHouseTestBase.cs:line 27
at MyNewHouse.Tests.Locations.CityAppService_Tests..ctor() in C:\WA\GpES\MyNewHouse\Tests\MyNewHouse.Tests\Locations\CityAppService_Tests.cs:line 24
at MyNewHouse.Tests.Auctions.AuctionAppService_Tests..ctor() in C:\WA\GpES\MyNewHouse\Tests\MyNewHouse.Tests\Auctions\AuctionAppService_Tests.cs:line 22
----- Inner Stack Trace -----
at Effort.Provider.EffortProviderConfiguration.RegisterDbConfigurationEventHandler()
at Effort.Provider.EffortProviderConfiguration.RegisterProvider()
at Effort.DbConnectionFactory..cctor()
----- Inner Stack Trace -----
at System.Data.Entity.Infrastructure.DependencyResolution.DbConfigurationManager.AddLoadedHandler(EventHandler`1 handler)
at System.Data.Entity.DbConfiguration.add_Loaded(EventHandler`1 value)
at Effort.Provider.EffortProviderConfiguration.RegisterDbConfigurationEventHandler()
Result Message:
System.TypeInitializationException : The type initializer for 'Effort.DbConnectionFactory' threw an exception.
---- Effort.Exceptions.EffortException : The Effort library failed to register its provider automatically, so manual registration is required.
a) Call the Effort.Provider.EffortProviderConfiguration.RegisterProvider() method at entry point of the application
or
b) Add the following configuration to the App.config file:
<system.data>
<DbProviderFactories>
<add name="Effort.Provider"
invariant="Effort.Provider"
description="Effort.Provider"
type="Effort.Provider.EffortProviderFactory, Effort" />
</DbProviderFactories>
</system.data>
<entityFramework>
<providers>
<provider invariantName="Effort.Provider"
type="Effort.Provider.EffortProviderServices, Effort" />
</providers>
</entityFramework>
-------- System.InvalidOperationException : The Entity Framework was already using a DbConfiguration instance before an attempt was made to add an 'Loaded' event handler. 'Loaded' event handlers can only be added as part of application start up before the Entity Framework is used. See http://go.microsoft.com/fwlink/?LinkId=260883 for more information.
I hope I helped you. Gp
Going further to this point, I got the exception received on my unit test.
When I run this code:
[Fact]
public async Task GetPropertyFull_Test() {
PropertyForSale entity = null;
await UsingDbContextAsync(AbpSession.TenantId, async context => {
entity = await context.REProperties.OfType<PropertyForSale>()
.FirstAsync(u => (u.TenantId == AbpSession.TenantId));
});
. . .
}
The exception I receive when fetching the entity is:
System.TypeInitializationException : The type initializer for 'Effort.DbConnectionFactory' threw an exception.
---- Effort.Exceptions.EffortException : The Effort library failed to register its provider automatically, so manual registration is required.
a) Call the Effort.Provider.EffortProviderConfiguration.RegisterProvider() method at entry point of the application
or
b) Add the following configuration to the App.config file:
<system.data>
<DbProviderFactories>
<add name="Effort.Provider"
invariant="Effort.Provider"
description="Effort.Provider"
type="Effort.Provider.EffortProviderFactory, Effort" />
</DbProviderFactories>
</system.data>
<entityFramework>
<providers>
<provider invariantName="Effort.Provider"
type="Effort.Provider.EffortProviderServices, Effort" />
</providers>
</entityFramework>
But If I add this line of code (theoretically not neede) at the beginning of the code, all works:
[Fact]
public async Task GetPropertyFull_Test() {
var dummyService = Resolve<IUserAppService>(); // why?
PropertyForSale entity = null;
await UsingDbContextAsync(AbpSession.TenantId, async context => {
...
}
Anybody can help me?
Tnx, gp
Thanks again for your reply. I went on with tests and I think it might be a bug somewhere (in your code?) as I found a workaround to solve the issue:
if I ran the same test by calling first a _userAppService.FindUser(...), everything works! See my working new testing code:
[Fact]
public async Task GetPropertyFull_Test() {
PropertyForSale entity = null;
await UsingDbContextAsync(AbpSession.TenantId, async context => {
entity = await context.REProperties.OfType<PropertyForSale>()
.FirstAsync(u => (u.TenantId == AbpSession.TenantId));
});
// only needed for a possible bug!
await _userAppService.FindUser(long.MaxValue); // only needed for a possible bug!
// test
var output = await _pfsAppService.GetPropertyFull(entity.Id);
output.ShouldNotBeNull();
output.Id.ShouldBe(entity.Id);
}
This test works! But if I comment out code lines related to user, specifically the line:
var userDto = await _userAppService.FindUser(long.MaxValue); // only needed for a possible bug!
the test fails.
The test works even if I move the 'finduser' code in the Test's constructor leaving my test method clean:
public PfsAppService_Tests() {
_pfsAppService = Resolve<IPfsAppService>();
// only needed for a possible bug!
_userAppService = Resolve<IUserAppService>();
_userAppService.FindUser(long.MaxValue);
}
[Fact]
public async Task GetPropertyFull_Test() {
PropertyForSale entity = null;
await UsingDbContextAsync(AbpSession.TenantId, async context => {
entity = await context.REProperties.OfType<PropertyForSale>()
.FirstAsync(u => (u.TenantId == AbpSession.TenantId));
});
// test
var output = await _pfsAppService.GetPropertyFull(entity.Id);
output.ShouldNotBeNull();
output.Id.ShouldBe(entity.Id);
}
What I miss?
Well,
//Seed initial data for default tenant
AbpSession.TenantId = 1;
UsingDbContext(context =>
{
new TenantRoleAndUserBuilder(context, AbpSession.GetTenantId()).Create();
new DefaultTenantBusinessDataCreator(context, AbpSession.GetTenantId()).Create(20); // Gp - create app business data
});
It is you original code. My code is just the last line (// Gp ...)
TenantId is correctly 1, when I extract it from DB:
PropertyForSale pfs = null;
await UsingDbContextAsync(async context => {
pfs = await context.REProperties.OfType<PropertyForSale>()
.Include(p => p.Owner)
.Include(p => p.Solicitor)
.Include(p => p.ZipCode)
.Include(p => p.City)
.Include(p => p.Attachments)
.Include(p => p.SaleAgreement)
.FirstAsync();
});
But when I execute the line
_myRepository.FirstOrDefaultAsync(p => p.Id == pfsId)
or
AbpSession.TenantId = 1;
. . .
_myRepository.FirstOrDefaultAsync(p => p.Id == pfsId)
it returns nothing.
even the code _myRepository.GetAllList() returns an empty list.
This is the same issue I have with tenant data.
All my tests running on non-tenant data works, but when I call the AppService working on tenant data it always return 0.
I tried to disable filters, set the correct tenant Id without success.
This is the test
public async Task GetShowCase_Test() {
// I call the DB just to be sure the query returns the correct # of items (16)
IList<PropertyForSale> dbShowCase = null;
await UsingDbContextAsync(async context => {
dbShowCase = await context.REProperties.OfType<PropertyForSale>()
.Include(p => p.SaleAgreement)
.Where(p => p.SaleAgreement == null)
.ToListAsync();
});
var input = new GetPfsShowCaseInput {
MaxResultCount = 100,
SkipCount = 0
};
var output = await _pfsAppService.GetShowCase(input);
output.Items.Count.ShouldBeGreaterThan(0); // this fails as items are 0!
}
This is the service method that works when I run it normally
public async Task<GetPfsShowCaseOutput> GetShowCase(GetPfsShowCaseInput input) {
// this returns 0 tiems during unit test
var items = _propertiesManager.GetShowCase(input.SkipCount, input.MaxResultCount, input.Sorting);
return new GetPfsShowCaseOutput {
Items = items.MapTo<ReadOnlyCollection<PropertyForSaleDto>>()
};
}
}
And this is the Repository code:
public IQueryable<PropertyForSale> GetShowCase(int skipCount, int maxResultCount, string sorting = null) {
var query = GetAll()
.Where(p => (p.ShowOnline && (p.SaleAgreement == null)));
// sorting and paging
query = query
.OrderByDescending(p => p.ShowOnlineDate);
query = query
.Skip(skipCount)
.Take(maxResultCount);
return query;
}
I try to reply by myself hoping some feedback about my solution.
[DependsOn(typeof(MyProjectCoreModule), typeof(AbpAutoMapperModule))]
public class MyProjectApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
// --- MY CODE
var mapperConfiguration = new MapperConfiguration(cfg => {
cfg.AddProfile(new MyProjectMapperProfile()); // <= here my custom mapping
});
var mapper = mapperConfiguration.CreateMapper();
IocManager.IocContainer.Register(
Castle.MicroKernel.Registration.Component.For<IMapper>().Instance(mapper)
);
// --- MY CODE
}
}
public class UserAppService : MyNewHouseAppServiceBase, IUserAppService {
. . .
public UserAppService(IRepository<User, long> userRepository, AutoMapper.IMapper mapper) {
. . .
}
public async Task<ListResultOutput<UserListDto>> GetUsers() {
var users = await _userRepository.GetAllListAsync();
return new ListResultOutput<UserListDto>(
// USE THE INJECTED MAPPER
_mapper.Map<List<UserListDto>>(users)
);
}
}
What do you think about this solution?
Tnx gp
I am newbie of ASP.NET BoilerPlate (ABP) and I am trying to understand how to create custom mappings using AutoMapper.
if I have two classes like the following where I want the property AB to be automapped as a join of A and B:
[AutoMapTo(typeof(DestClass)] // <= do I need it for this case?
public class SourceClass {
public string A { get; set; }
public string B { get; set; }
}
public class DestClass {
public string AB { get; set; }
}
I image I have to init automapper properly by using this kind of code:
Mapper.CreateMap<SourceClass, DestClass>()
.ForMember(dest => dest.AB,
opts => opts.MapFrom(src => (src.A + ", " + src.B)));
My question is: As I am in my web module and the classes are used by my AppService, where do I place the automapper init code above? Also, do I need to decorate the classes with the [AutoMap] attrib (I think, no)?
Thank you