Testing AppService: System.ObjectDisposedException - abp

Using the abp.io module template
Using the sqlite :memory: provider for my tests. Getting this error when I attempt to query using the IRepository<TEntity, Guid> service. It occurs whether I use it directly in a test method, or the instance injected into the service.
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.
Does anyone know what is causing this error, I can't seem to figure it out. Have I mis-configured something in the test modules?
HolidaySchedule schedule = await _holidayScheduleRepository.GetAsync(x => x.TenantId == tenantId
&& x.Id == id);

In case anyone has this issue, my problem was that I wasn't using the unit of work properly. My test cases needed to be wrapped in a WithUnitOfWork.. block which I overlooked.
await WithUnitOfWorkAsync(async () =>
{
ISomeService service = GetRequiredService<ISomeService>();
int result = await service.DoSomethingAsync();
Assert.Equal(5, result);
});

Related

HostListener and Angular Universal

I'm trying to listen to a MessageEvent sent with postMessage in my Angular 2 component.
My first attempt was simply doing:
window.addEventListener("message", this.handlePostMessage.bind(this));
And then in ngOnDestroy:
window.removeEventListener("message", this.handlePostMessage.bind(this));
However this didn't work as expected. If I navigated to another route and back, there would be two event listeners registered.
So instead I've been trying to decorate the method with HostListener, but I can't get this working when using prerendering (Angular Universal with .NET Core using the asp-prerender-module).
#HostListener('window:message', ['$event'])
private handlePostMessage(msg: MessageEvent) {
...
}
That gives me the following error on page load:
Exception: Call to Node module failed with error: Prerendering failed because of error: ReferenceError: MessageEvent is not defined
Is there a workaround for this?
You're getting this error because MessageEvent is not defined. You must import whatever file defines this.
My #HostListeners look like this:
#HostListener("window:savePDF", ["$event"]) savePDF(event) {
this.savePDFButtonPushed();
}
and you can read more about them here:
https://angular.io/guide/attribute-directives
However, I'm currently experiencing the same issue you are -- that if I navigate to another route and back, I now receive two events. And that is using #HostListener. :-( However I haven't upgraded Angular in a while (currently using 4.4.6), so maybe they've fixed it since that release.
**Edit: Just upgraded to Angular 5.1.0. The 'duplicate events' #HostListener issue remains. :-(
Edit #2: I tried also using window.addEventListener like you tried, and also had the same issue, despite using window.removeEventListener in ngOnDestroy().
This lead me to dig a little deeper, where I found some code I had added to listen to messages from a child iFrame. Any chance you have something similar in your code?
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to messages from child window ("unsign" and "savePDF") and pass those along as events to Angular can pick them up in its context
eventer(messageEvent,function(e) {
window.dispatchEvent( new Event( e.data ) );
},false);
This had been in my page's constructor. I protected it so it only executed the first time the page was constructor, and now all is well.

Angular Controller can inject service just fine but $injector.get can't?

I have an extremely edge case scenario where I have a callback method I have to define during config. Which means no scope, no factories, etc... My work around is to use the root injector ($injector) and get my other modules at runtime.
However, when I call $injector.get('myServiceName') in my call back (after the application is running) I get "unknown provider". The same service has no problem (and actually is) being injected into a before my line of code is running. If I call $injector.get("myServiceNameProvider") then I can get the provider back in my callback.. But another service that only has a factory I can't get at all.
So in this extremely bad practice, how can I snag the service I configured. Heck I can't even seem to get $rootScope..
Angular inits providers first, then factories/services - services are not available in app.config.
You can deo like this:
app.config(...
window.on('scroll', function() {
// this is executed later
$injector.get()...
})
Or use app.run where services are available.
I think I had similar problem few months ago... I need to construct breadcrumbs, but they had to be created in config phase (ui-router). I have done it like this (breadcrumbs-generation-service.provider.js):
var somethingYouHaveToHaveLater = undefined;
function BreadcrumbsGenerationService () {
this.createStateData = createStateData;
function createStateData (arg) {
somethingYouHaveToHaveLater = arg;
};
}
function BreadcrumbsGenerationServiceProvider () {
this.$get = function BreadcrumbsGenerationServiceFactory () {
return new BreadcrumbsGenerationService();
}
}
angular
.module('ncAdminApp')
.provider('BreadcrumbsGenerationService', BreadcrumbsGenerationServiceProvider);
Because service is used inside Angular configs, needs to be injected as provider to be available in config phase: Similar SO Question. Despite the fact is registered as BreadcrumbsGenerationService needs to be injected as BreadcrumbsGenerationServiceProvider to config phase and used with $get():
BreadcrumbsGenerationServiceProvider.$get().createStateData(someParams);
But in controller, inject it without Provider suffix (BreadcrumbsGenerationServic) and it behaves as normal service.

Easy Mock issue with Blob

We are using Easy Mock for creating JUnit test case in java with H2 database.
As code of fetching the Blob content is specific to Oracle and getting the following error.
ClassCastException: Cannot cast org.h2.jdbc.JdbcResultSet (id=72) to oracle.jdbc.driver.OracleResultSet
public BLOB getBLOB(String field) throws SQLException {
try {return ((OracleResultSet) rs).getBLOB(field);
} catch (NullPointerException e) {}}
Bit stuck with this as how can we handle this in Easy Mock without changing the above code.
You are doing something weird here. If you are using EasyMock to mock the blob, you should mock OracleResultSet, not JdbcResultSet.
You don't need H2 here. Since you are mocking.
As a side note: Please remote the empty catch of the NPE. You are heavily shooting yourself in the foot when doing that.
We are not mocking JdbcResultSet.In this case we are fetching the blob contents from database so we can't mock OracleResultSet. Removed the code from Empty catch.

Block or extend Breeze metadata auto fetching

Current application - Angular application with Breeze. Application has ~7 entity managers and different data domains (metadata). When application runs we trying to fetch entity managers, like:
app.run(['$rootScope', 'datacontext1', ... ], function($rootScope, datacontext1, ...) {
datacontext1.loadMetadata();
...
datacontext7.loadMetadata();
}
Every datacontext has its own entity manager and loadMetadata is:
function loadMetadata() {
manager.fetchMetadata().then(function(mdata) {
if (mdata === 'already fetched') {
return;
}
...
applyCustomMetadata(); // Do some custom job with metadata/entity types
});
}
Metadata comes from server asynchronously. Few module has really big metadata, like 200Kb and takes some time for loading and apply to entity manager. Its possible that first Breeze data request executed in same entity manager will be started before this loadMetadata operation finished and as I understand Breeze automatically fetch metadata again. Usually its not a problem, Metadata end point cached on server, but sometimes it produces very strange behavior of Breeze - EntityManager.fetchMetadata resolve promise as "already fetched" and in this case applyCustomMetadata() operation can not be executed.
As I understand problem is inside Breeze and approach its used to resolve metadata promise (seems to be http adapter is singleton and second request override metadata with "already fetched" string and applyCustomMetadata() operation never executes).
Need to figure out some way to resolve issue without significant changes in application.
Logically need to delay full application from using entity managers while loadMetadata done. Looking for any way on Breeze level to disable auto fetch metadata if its already in progress (but not interrupt request, just wait and try again after some time). Any other ideas are fine as well.
Why are you allowing queries to execute before the metadata is loaded? Therein lies your problem.
I have an application bootstrapper that I expose through a global variable; none of my application activities depending on the Entity Manager are started until preliminary processes complete:
var bootstrapper = {
pageReady: ko.observable(false)
};
initBootstrapper();
return bootstrapper;
function initBootstrapper() {
window.MyApp.entityManagerProvider.initialize() // load metadata, lookups, etc
.then(function () {
window.MyApp.router.initialize(); // setup page routes, home ViewModel, etc
bootstrapper.pageReady(true); // show homepage
});
};
Additionally, depending on the frequency of database changes occurring in your organization, you may wish to deliver the metadata to the client synchronously on page_load. See this documentation for further details:
http://breeze.github.io/doc-js/metadata-load-from-script.html

breezejs: dynamically switching between OData and WebAPI

I'm facing a bit of a tricky situation here. I have two services that my application needs to access to. One is a pure ODATA service and the other is a WebAPI (with Breeze controller) service.
My application is designed around the AngularJS modules and breeze is injected into two differerent single-instance services :
angular.module('domiciliations.services').
factory('domiciliationService', function (breeze) {
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
//more initialization goes here
//then query methods go here
}
and
angular.module('person.services').
factory('personService', function (breeze) {
breeze.config.initializeAdapterInstances({ "dataService": "OData" });
//more initialization goes here
//then query methods go here
}
Now obviously the problem is that once the person service has been instanciated, the domiciliations service then uses OData because the config was overwritten.
So, what is the general approach for tackling this issue ? Is there a way to isolate the config ?
So far the only way I can think of, is to call the initializeAdapterinstances method each time a query method is called, which is not really desirable.
EDIT
As per Jay's recommandation I'm now using DataService. I'm having an error though in ctor.resolve at the line:
ds.jsonResultsAdapter = ds.jsonResultsAdapter || ds.adapterInstance.jsonResultsAdapter;
ds.adapterInstance is null, therefore this throws an exception. But I don't understand why it's null.
Here's what I've done:
var service = new breeze.DataService({
serviceName: 'http://localhost:16361/api/mandates',
adapterName: 'WebApi'
});
var manager = new breeze.EntityManager({ dataService: service });
//this is the line causing the later exception:
manager.fetchMetadata().then(function () { ... }
Did I forget to do something ?
Good question!
The initializeAdapterInstance method is really intended to setup the 'default' adapters.
If you need to have multiple adapters and apply them on a per query basis then see the DataService documentation especially the 'adapterName' property in the ctor. You can have two DataServices, one for OData and one for WebApi. You can then use either for any query via the EntityQuery.using method.
var odataDataService = new DataService({
serviceName: "Foo",
adapterName: "OData"
});
var webApiDataService = new DataService({
serviceName: "Bar",
adapterName: "WebApi"
});
var query1 = EntityQuery.from(...).where(...);
var query2 = EntityQuery.from(...).where(...);
entityManager.executeQuery(query1.using(odataDataService)).then(...)
entityManager.executeQuery(query2.using(webApiDataService)).then(...)

Resources