Hi @ryancyq
I added an interface for the folder manager (and converted the manager to implement the interface).
using Syntaq.Falcon.AccessControlList;
using Syntaq.Falcon.Folders.Dtos;
using System.Threading.Tasks;
namespace Syntaq.Falcon.Folders
{
public interface IFolderManager
{
Task CreateOrEditFolder(ACL ACL, Folder Folder);
Task CreateAndOrFetchFolder(ACL ACL, Folder Folder);
Task Move(MoveFolderDto moveFolderDto);
}
}
And then I'm resolving the interface at the top of the unit test.
public class FolderManager_Tests : AppTestBase
{
private readonly IFolderManager _folderManager;
public FolderManager_Tests()
{
_folderManager = Resolve<IFolderManager>();
}
And here is the stack trace
[27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] System.ObjectDisposedException : Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] Object name: 'FalconDbContext'. [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] Stack Trace: [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed() [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] at Microsoft.EntityFrameworkCore.DbContext.get_Model() [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] at Microsoft.EntityFrameworkCore.Internal.InternalDbSet'1.get_EntityType()
\[27/12/2018 11:14:34 AM Informational\] \[xUnit\.net 00:00:22\.43\] at Microsoft\.EntityFrameworkCore\.Internal\.InternalDbSet'1.get_EntityQueryable() [27/12/2018 11:14:34 AM Informational] [xUnit.net 00:00:22.43] at Microsoft.EntityFrameworkCore.Internal.InternalDbSet'1.System.Linq.IQueryable.get_Provider()
\[27/12/2018 11:14:34 AM Informational\] \[xUnit\.net 00:00:22\.43\] at System\.Linq\.Queryable\.Any\[TSource\]\(IQueryable'1 source, Expression'1 predicate)
\[27/12/2018 11:14:34 AM Informational\] \[xUnit\.net 00:00:22\.43\] D:\Source\Syntaq\.Falcon\src\Syntaq\.Falcon\.Core\Folders\FolderManager\.cs\(92\,0\): at Syntaq\.Falcon\.Folders\.FolderManager\.CreateAndOrFetchFolder\(ACL ACL\, Folder Folder\)
\[27/12/2018 11:14:34 AM Informational\] \[xUnit\.net 00:00:22\.43\] D:\Source\Syntaq\.Falcon\test\Syntaq\.Falcon\.Tests\Folders\FolderManager\_Tests\.cs\(29\,0\): at Syntaq\.Falcon\.Tests\.Folders\.FolderManager\_Tests\.Should\_Fetch\_Folder\(\)
\[27/12/2018 11:14:34 AM Informational\] \[xUnit\.net 00:00:22\.43\] \-\-\- End of stack trace from previous location where exception was thrown \-\-\-\
@ryancyq & @hikalkan thank you both for your responses and your discussion on the pull request.
The idea behind our use-case is that as the host, we define the application editions and specify the features each edition has. Tenants then being assigned different editions thus get access to various features as defined by the assigned edition. As the host, having access to all of the platforms features is beneficial because we can test functionality, check that it's working after updates, etc. myself as a developer of our app, I use a host user account, and our automated functional testing also uses a host user account, and both of these are done this way because they have access to all features and functions of the app. This is however majorly disrupted if blocked by the feature checkers.
Another point for consideration is that features restricted by the features system, may not be, and in our application, certainly aren't, exclusively designed to work only for tenant users. A host user using a given feature doesn't change the operation or outcome of the feature, even though it has a null tenant id.
However, if the status quo remains, and feature checking is left as a tenant only scope, one thing that would be very beneficial to future devs, would be explicit exception messages. Currently, a feature checker on an MVC controller returns a 500 error, and on an application service, also returns a 500 error but is caught by error handling and thus displays the generic "An internal error occurred during your request!"
Thanks, David
Hi all,
I'm in the process of building out unit tests for the new functionality that we've added to our .net zero project. So far, for the app services, this is going swimmingly. However we have several pieces of functionality that sit in domain layer managers, and I'm struggling to implement unit tests for those.
My first question is, is there an ideal or proper way of implementing a unit test in .net zero for domain layer managers?
Where I've managed to get so far is creating an interface for the domain manager, which allows it to be resolvable in the unit test project. When running the test, it correctly creates an instance of the manager, but then fails due to a disposed object error on a repository. This isn't an issue when running a unit test on an app service that calls a method inside of a manager that uses a repository, but I'm not sure what the missing difference is between an app service unit test and a domain manager unit test.
If I'm on the right path with this approch, how does one correctly resolve a domain manager such that it correctly used the test context? (Which I guessing is what fails with the disposed object error)
Thanks,
David
Hi Guys,
I'm in the process of setting up editions, and creating and implementing features for the editions.
I'm currently trying to restrict access to certain views/app services based on needing to have a required feature. Using the following implementations:
featureDependency: new SimpleFeatureDependency(true, "App.AppBuilder")
I can hide menu items
[RequiresFeature("App.AppBuilder")]
or
if (await FeatureChecker.IsEnabledAsync("App.AppBuilder")) { throw new AbpAuthorizationException("You don't have this feature: App Builder"); }
I can restrict access to an MVC controller or App Service.
These work well and out of the box for tenant users, however, I am finding that host users get blocked from the controllers that have these feature checks implemented on them.
Do I need to implement the checks differently or is there some additional code that I need to add that allows host users access to feature restricted areas without having an edition assigned?
Thanks, David
Hi Guys,
I've recently begun building out unit tests in our .net zero project and I don't currently fully understand how the unit tests manage user context.
I've noticed that the AbpSession.UserId value when the tests are running is set to user 2. How does the testing framework chose this user and set as user context?
Is it possible to change which user context all the tests or certain tests run under?
Thanks,
David
Hi Mitch,
I realise this post is 10 months old but in case you're still stuck with SendGrid or for other readers, I've got a working SendGrid configuration in .Net Zero and my solution is also hosted in Azure and SendGrid works from Production as well as in Dev.
On the Email(SMTP) tab under admin -> settings, I have it configured as follows:
Hope this helps :)
Hi Maliming,
Thank you for your response and help.
As noted by Hikalkan in the Git Link:
Only default values are not saved (because they are default and hard-coded in your code) and when you get a feature's value, this default value is returned.
It would be good if this was stated in the documention for features: Feature Management
Hi Maliming
Here is the data in my AbpFeatures table:
Id CreationTime CreatorUserId Discriminator Name Value EditionId TenantId
1 2018-03-16 14:38:16.4764368 NULL EditionFeatureSetting App.ChatFeature true 1 NULL
2 2018-03-16 14:38:16.5210188 NULL EditionFeatureSetting App.ChatFeature.TenantToTenant true 1 NULL
3 2018-03-16 14:38:16.5225230 NULL EditionFeatureSetting App.ChatFeature.TenantToHost true 1 NULL
4 2018-10-10 12:14:40.9736974 1 EditionFeatureSetting App.ChatFeature true 2 NULL
5 2018-10-10 12:14:40.9881633 1 EditionFeatureSetting App.ChatFeature.TenantToHost true 2 NULL
6 2018-10-10 12:14:40.9917917 1 EditionFeatureSetting App.ChatFeature.TenantToTenant true 2 NULL
7 2018-10-10 12:14:40.9993621 1 EditionFeatureSetting App.TestCheckFeature2 false 2 NULL
9 2018-10-10 13:03:44.7374498 1 EditionFeatureSetting App.SubmissionLimitAmount 500 2 NULL
The new custom feature, SubmissionLimitAmount, only shows up for Edition 2, but not for Edition 1, even though they both now have that feature. Edition 2 has a non-default value set for its SubmissionLimitAmount, while Edition 1 has the default value, and this would be why one shows up and the other doesn't?
Update: So my current understanding that the features will only show up in the AbpFeatures table when a non-default value is specified. Using the FeatureChecker.GetValueAsync functionality will return either the default value (presumably from the feature definition) or the non-default value from the database.
Hi Guys,
I've added a new feature into the application, as shown below:
public static class AppFeatures
{
public const string SubmissionLimit = "App.SubmissionLimit";
public const string StarterSubmissionLimit = "App.StarterSubmissionLimit";
}
public class AppFeatureProvider : FeatureProvider
{
public override void SetFeatures(IFeatureDefinitionContext context)
{
var submissionLimit = context.Create(
AppFeatures.SubmissionLimit,
defaultValue: "true",
displayName: L("SubmissionLimit"),
inputType: new CheckboxInputType()
);
submissionLimit.CreateChildFeature(
AppFeatures.StarterSubmissionLimit,
defaultValue: "100",
displayName: L("StarterSubmissionLimit"),
inputType: new SingleLineStringInputType(new NumericValueValidator(0, 100))
);
}
}
I am able to see these new features in the edit edition modal and I am able to select them, however the new features don't appear in the AbpFeatures table as having been assigned to the edition - is there something that I am missing here?