Can't update users email address or password using Thinktecture IdMgr + MembershipReboot. - thinktecture

When I edit a user in Thinktecture IdManager I can change their name, and age and other "custom" properties but when I try to change their email address or password my custom Membership Reboot repository update method is called once to save the change and then again to revert the change.
The controller is called twice by AutoFac container middleware for some reason.
There is only 1 HTTP post coming from the IdMgr application so it's not a client side issue.
The first stack trace is...
Gaist.Authentication.dll!Gaist.Authentication.MR.MembershipRebootRepository.Update(Gaist.Authentication.Mongo.Models.CustomUser item) Line 71 C#
[External Code]
IdentityManager.MembershipReboot.dll!IdentityManager.MembershipReboot.MembershipRebootIdentityManagerService<Gaist.Authentication.Mongo.Models.CustomUser,Gaist.Authentication.Mongo.Models.CustomGroup>.SetPassword(Gaist.Authentication.Mongo.Models.CustomUser account, string password) Line 235 C#
IdentityManager.dll!IdentityManager.ExpressionPropertyMetadata<Gaist.Authentication.Mongo.Models.CustomUser,string>.Set(object instance, string value) Line 87 C#
IdentityManager.dll!IdentityManager.PropertyMetadataExtensions.TrySet(IdentityManager.PropertyMetadata property, object instance, string value, out IdentityManager.IdentityManagerResult result) Line 137 C#
IdentityManager.dll!IdentityManager.PropertyMetadataExtensions.TrySet(System.Collections.Generic.IEnumerable<IdentityManager.PropertyMetadata> properties, object instance, string type, string value, out IdentityManager.IdentityManagerResult result) Line 123 C#
IdentityManager.MembershipReboot.dll!IdentityManager.MembershipReboot.MembershipRebootIdentityManagerService<Gaist.Authentication.Mongo.Models.CustomUser,Gaist.Authentication.Mongo.Models.CustomGroup>.SetUserProperty(System.Collections.Generic.IEnumerable<IdentityManager.PropertyMetadata> propsMeta, Gaist.Authentication.Mongo.Models.CustomUser user, string type, string value) Line 590 C#
IdentityManager.MembershipReboot.dll!IdentityManager.MembershipReboot.MembershipRebootIdentityManagerService<Gaist.Authentication.Mongo.Models.CustomUser,Gaist.Authentication.Mongo.Models.CustomGroup>.SetUserPropertyAsync(string subject, string type, string value) Line 503 C#
IdentityManager.dll!IdentityManager.Api.Models.Controllers.UserController.SetPropertyAsync(string subject, string type) Line 205 C#
[External Code]
IdentityManager.dll!IdentityManager.Configuration.Hosting.KatanaDependencyResolver.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Line 35 C#
[External Code]
IdentityManager.dll!IdentityManager.Configuration.Hosting.AutofacContainerMiddleware.Invoke(System.Collections.Generic.IDictionary<string,object> env) Line 51 C#
[External Code]
IdentityManager.dll!Owin.IdentityManagerAppBuilderExtensions.UseIdentityManager(Microsoft.Owin.IOwinContext ctx, System.Func<System.Threading.Tasks.Task> next) Line 55 C#
[Resuming Async Method]
[External Code]
The second stack trace is ...
Gaist.Authentication.dll!Gaist.Authentication.MR.MembershipRebootRepository.Update(Gaist.Authentication.Mongo.Models.CustomUser item) Line 71 C#
[External Code]
IdentityManager.MembershipReboot.dll!IdentityManager.MembershipReboot.MembershipRebootIdentityManagerService<Gaist.Authentication.Mongo.Models.CustomUser,Gaist.Authentication.Mongo.Models.CustomGroup>.SetUserPropertyAsync(string subject, string type, string value) Line 511 C#
IdentityManager.dll!IdentityManager.Api.Models.Controllers.UserController.SetPropertyAsync(string subject, string type) Line 205 C#
[External Code]
IdentityManager.dll!IdentityManager.Configuration.Hosting.KatanaDependencyResolver.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Line 35 C#
[External Code]
IdentityManager.dll!IdentityManager.Configuration.Hosting.AutofacContainerMiddleware.Invoke(System.Collections.Generic.IDictionary<string,object> env) Line 51 C#
[External Code]
IdentityManager.dll!Owin.IdentityManagerAppBuilderExtensions.UseIdentityManager(Microsoft.Owin.IOwinContext ctx, System.Func<System.Threading.Tasks.Task> next) Line 55 C#
[Resuming Async Method]
[External Code]

This was happening because the MembershipRebootIdentityManagerService implementation that comes out of the box was assuming that the repository would be based on Entity Framework and that calling save twice would be working on the same instance of an EF context and therfore the same entity.
My repo implementation didn't work that way so it was loading an unsaved entity and then overwriting the settings.
I had to frig my repository to hold onto the entity that's being edited for the lifetime of the repo.

Related

How to stop EF Core DbContext.SaveChanges auto committing transactions?

I'm using EF Core in a netcoreapp3 app.
(I'm actually using DevArt's latest libs for Postgres but I don't think that's relevant here).
If I begin a transaction (repeatable read in this case):
var pg_conn = this.m_db.GetPGConnection();
pg_conn.Open();
// DevArt override BeginTransaction and allow you to pass in the isolation level
using (var trans = pg_conn.BeginTransaction(this.m_isolation))
{
trans.StateChanged += Trans_StateChanged;
try
{
T result = m_dlg(this.m_db); // This delegate does stuff and calls db.SaveChanges
trans.Commit(); // By the time you get here the transaction has been auto committed and disposed
return result;
}
do some stuff and call SaveChanges the transaction has been committed and disposed.
I attached an event to the transaction's StateChanged event to see where the call was coming from. The stack trace shows that the call is coming from MS EF (not DevArt):
WFDB.dll!WFDB.Contexts.TransactionRepeater<WFDB.Contexts.Workflow_DBContext, object>.Trans_StateChanged(object sender, Devart.Common.TransactionStateChangedEventArgs e) Line 249 C#
Devart.Data.dll!Devart.Common.DbTransactionBase.OnStateChanged(Devart.Common.TransactionAction action, System.Data.Common.DbConnection connection) Unknown
Devart.Data.PostgreSql.dll!Devart.Data.PostgreSql.PgSqlTransaction.Commit() Unknown
Devart.Data.PostgreSql.Entity.EFCore.dll!Devart.Common.Entity.cx.Commit() Unknown
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Storage.RelationalTransaction.Commit() Unknown (The culprit? How do I stop this call?)
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(Microsoft.EntityFrameworkCore.DbContext _, (System.Collections.Generic.IEnumerable<Microsoft.EntityFrameworkCore.Update.ModificationCommandBatch>, Microsoft.EntityFrameworkCore.Storage.IRelationalConnection) parameters) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Storage.Internal.NoopExecutionStrategy.Execute<System.ValueTuple<System.__Canon, System.__Canon>, int>((System.__Canon, System.__Canon) state, System.Func<Microsoft.EntityFrameworkCore.DbContext, (System.__Canon, System.__Canon), int> operation, System.Func<Microsoft.EntityFrameworkCore.DbContext, (System.__Canon, System.__Canon), Microsoft.EntityFrameworkCore.Storage.ExecutionResult<int>> verifySucceeded) Unknown
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(System.Collections.Generic.IEnumerable<Microsoft.EntityFrameworkCore.Update.ModificationCommandBatch> commandBatches, Microsoft.EntityFrameworkCore.Storage.IRelationalConnection connection) Unknown
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(System.Collections.Generic.IList<Microsoft.EntityFrameworkCore.Update.IUpdateEntry> entries) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(System.Collections.Generic.IList<Microsoft.EntityFrameworkCore.Update.IUpdateEntry> entriesToSave) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(bool acceptAllChangesOnSuccess) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.DbContext.SaveChanges(bool acceptAllChangesOnSuccess) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.DbContext.SaveChanges() Unknown
WFDB.dll!WFDB.Contexts.Workflow_DBContext.SaveChanges() Line 107 C#
I don't want the transaction to auto commit. How can it be prevented? There surely must be some setting in EF Core to stop that?

How to create a LocalDB instance for NEventStore

I'm trying to use LocalDb with NEventStore but, even though I think I have set-up the database correctly, I keep getting the following exception:
NEventStore.Persistence.StorageUnavailableException: Invalid object name 'Snapshots'.
In code I configure NEventStore to use the database like this:
this.EventStore = Wireup.Init()
.LogToOutputWindow()
.UsingInMemoryPersistence()
.UsingSqlPersistence("DefaultConnection")
.WithDialect(new MsSqlDialect())
.UsingJsonSerialization()
.LogToOutputWindow()
.Build();
I have the following database connection in my web.config file:
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\MyDatabase.mdf;Initial Catalog=MyDatabase;Integrated Security=True" providerName="System.Data.SqlClient" />
And using Visual Studio I've added an SqlServerDatabase (MyDatabase.mdf) to the App_Data folder of my Asp.net MVC 5 project. NEventStore seems to be able to open the database (if I remove MyDatabase.mdf from my project I get a different exception). But it seems its unable to initialize the database correctly. When I browse the database, after running into the error message, I see that no tables have been created.
What makes this extra strange is that, if this document is correct, Snapshots should be the second table made. So it seems it has no problem creating the first one.
The complete stack trace for the StorageUnavailableException
at NEventStore.Persistence.Sql.SqlDialects.PagedEnumerationCollection.OpenNextPage() in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlDialects\PagedEnumerationCollection.cs:line 200
at NEventStore.Persistence.Sql.SqlDialects.PagedEnumerationCollection.MoveToNextRecord() in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlDialects\PagedEnumerationCollection.cs:line 146
at NEventStore.Persistence.Sql.SqlDialects.PagedEnumerationCollection.System.Collections.IEnumerator.MoveNext() in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlDialects\PagedEnumerationCollection.cs:line 70
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at NEventStore.Persistence.Sql.SqlPersistenceEngine.GetSnapshot(String bucketId, String streamId, Int32 maxRevision) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlPersistenceEngine.cs:line 225
at NEventStore.Persistence.PipelineHooksAwarePersistanceDecorator.GetSnapshot(String bucketId, String streamId, Int32 maxRevision) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\PipelineHooksAwarePersistanceDecorator.cs:line 45
at NEventStore.AccessSnapshotsExtensions.GetSnapshot(IAccessSnapshots accessSnapshots, String bucketId, Guid streamId, Int32 maxRevision) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\AccessSnapshotsExtensions.cs:line 49
at CommonDomain.Persistence.EventStore.EventStoreRepository.GetSnapshot(String bucketId, Guid id, Int32 version) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\CommonDomain\Persistence\EventStore\EventStoreRepository.cs:line 147
at CommonDomain.Persistence.EventStore.EventStoreRepository.GetById[TAggregate](String bucketId, Guid id, Int32 versionToLoad) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\CommonDomain\Persistence\EventStore\EventStoreRepository.cs:line 54
at CommonDomain.Persistence.EventStore.EventStoreRepository.GetById[TAggregate](Guid id, Int32 versionToLoad) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\CommonDomain\Persistence\EventStore\EventStoreRepository.cs:line 44
at CapraLibraShop.DataModel.Repositories.UserAggregateRepository.UserWithEmailExists(EmailAddress emailAddress) in D:\Projects\C#\CapraLibraShop\CapraLibraShop.DataModel\Repositories\UserAggregateRepository.cs:line 22
at CapraLibraShop.Controllers.AccountController.Register() in D:\Projects\C#\CapraLibraShop\CapraLibraShop\Controllers\AccountController.cs:line 55
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
I literally found the answer two minutes after looking. But since I had a hard time Googling this answer I think it would be nice to place the answer here, instead of deleting the question.
I forgot to initialize the storage engine. I overlooked it because of the fluid syntax. The correct way to let NEventStore initialize the database is by including the InitializeStorageEngine method after you have selected the database type:
this.EventStore = Wireup.Init()
.LogToOutputWindow()
.UsingInMemoryPersistence()
.UsingSqlPersistence("DefaultConnection")
.WithDialect(new MsSqlDialect())
.InitializeStorageEngine() // The oh so important line!
.UsingJsonSerialization()
.LogToOutputWindow()
.Build();

Why am I getting Internal .NET Framework Data Provider error 1025 when passing Method to where?

I have a method that takes a generic TEntity which is overriden. It's signature is as follows:
public virtual Expression<Func<AclProject, bool>> ProjectFilter(params TEntity[] objs)
{
return (p) => objs.Select(o => o.ID).Contains(p.ID);
}
I then filter a query based on this:
from p in db.SomeDbSet where db.AclProjects.Where(ProjectFilter(p)).Any() select p
This results in a 1025 error. (note that it doesn't matter what the body of the ProjectFilter is, the error still occurs.
Any ideas why?
Thanks!

Class not registered errors with sharpDX

I'm trying some sharpDX examples and I;m getting this "Class not registered". I figure from the error its an os thing but I dont see why? I have installed the DX run-time as mentioned n the sharpDX page and I'm using windows7 64. This is a win32 app though.
error
An unhandled exception of type 'SharpDX.SharpDXException' occurred in SharpDX.dll
Additional information: HRESULT: [0x80040154], Module: [SharpDX.DirectInput], ApiCode: [DIERR_DEVICENOTREG/DeviceNotRegistered], Message: Class not registered
stack
SharpDX.dll!SharpDX.Result.CheckError() + 0x42 bytes
SharpDX.DirectInput.dll!SharpDX.DirectInput.DirectInput.CreateDevice(System.Guid arg0, out System.IntPtr arg1, SharpDX.ComObject arg2) + 0xee bytes
SharpDX.DirectInput.dll!SharpDX.DirectInput.Device.Device(SharpDX.DirectInput.DirectInput directInput, System.Guid deviceGuid) + 0x52 bytes
SharpDX.DirectInput.dll!SharpDX.DirectInput.CustomDevice<SharpDX.DirectInput.JoystickState,SharpDX.DirectInput.RawJoystickState,SharpDX.DirectInput.JoystickUpdate>.CustomDevice(SharpDX.DirectInput.DirectInput directInput, System.Guid deviceGuid) + 0x68 bytes
SharpDX.DirectInput.dll!SharpDX.DirectInput.Joystick.Joystick(SharpDX.DirectInput.DirectInput directInput, System.Guid deviceGuid) + 0x40 bytes
Code:
joystickState = new JoystickState();
Guid foundDevice = new Guid();
joystick = new Joystick(directInput, foundDevice);
You are not using correctly the API. The Guid should match a registered DirectInput Joystick Guid. Check more carefully the sample JoystickApp that is dealing exactly with this.

What is the proper use of EntityManager from a RESTEasy service? (SEAM, JBoss)

My project is a WAR project generated with seam-gen. It contains a RESTEasy web service class like this (simplified, only the relevant parts):
#Scope(ScopeType.APPLICATION)
public abstract class RestService {
#In
protected EntityManager entityManager;
#GET
#POST
#Produces("application/json")
public Object proxy() {
// invokes various subclass methods
// based on request parameters
// and returns the result
}
// further method and logic
}
And:
#Path("/my")
#Name("myRestService")
public class MyRestService extends RestService {
public Object login(/*...*/) {
User user = getUser(email);
// ...
Token token = user.getToken();
if (token != null) {
entityManager.remove(token);
}
token = new Token();
entityManager.persist(token);
user.setToken(token);
user.setLastlogin(new Date());
entityManager.persist(user);
// ...
}
private User getUser(String email) {
try {
return (User) entityManager
.createQuery("FROM User WHERE UPPER(email) = UPPER(:email)")
.setParameter("email", email)
.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
}
If i invoke the login method through a web browser, it finds the correct user (based on the get params), instantiates a Token for it (i can see at the STDOUT of Hibernate asking the databse for the next sequence), but the persist() method does not save the Token to the database, neither the modifications of the User object (token id, last login date).
I have googled this for two days now, here's what i could figure out:
my project uses SEAM managed transactions (components.xml):
<persistence:managed-persistence-context name="entityManager" auto-create="true"
persistence-unit-jndi-name="java:/MyEntityManagerFactory"/>
my project uses JTA for transaction handling (persistence.xml):
<persistence-unit name="MyProject" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider> ...
the EntityManager.persist() does NOT commit changes to the database, just queues changes to the current transaction (?)
the SEAM managed Transactions are tied to conversations by default
I tried to use .flush(), an exception was thrown saying that there is no transaction in progress.
I tried to use .joinTransaction() and .getTransaction().begin(), another exception was thrown saying that a JTA EntityManager can not access transactions.
Also tried to use different scope types on the class, or use the #Transactional annotation on my login() method, no luck.
Also tried to inject the EntityManager with the #PersistenceContext annotation, this resulted in an exception saying #PersistenceContext can only be used with session beans.
Also tried to mark my class as #Stateless, this resulted that i could not reach my service (404).
How should i persist my Entities within a RESTEasy service with EntityManager?
System specs:
JBoss 5.1.0 GA
SEAM 2.2.1 Final
Postgres 8.3
Please note that i'm totally new and inexperienced with JavaEE/JBoss/SEAM.
Any comment would be useful! Thanks.
You are detaching a managed field:
entityManager.remove(token);
Creating a new one:
token = new Token();
But here:
entityManager.persist(token);
Token has a relationship with User (I don't what that relationship is - oneToMany, oneToOne, are you cascading from User?, fetching, etc), but just calling persist on token does not re-establish that relationship.
Take a look here
http://www.objectdb.com/java/jpa/persistence/crud
The transactional annotation is important on the login method. This will ensure that the transaction interceptor is creating a transaction if neccessary. (if there is no transaction yet). The easiest way to find out if the interceptor is applied would be to debug into the login method and check the stack. I'm not sure how the class is called but i will update this post as soon as i'm at work to check it out.
If this interceptor is not there it means that you are not using seam transactions. The extract of your components.xml is not showing that you do so.
Martin
Updated:
So here's the stacktrace. Take a look at the TransactionInterceptor if you do not have this in your stack you have no transaction management.
Daemon Thread [http-18081-1] (Suspended (breakpoint at line 170 in QueryHome))
QueryHome.getCandidatesCount() line: 170
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
Reflections.invoke(Method, Object, Object...) line: 22
RootInvocationContext.proceed() line: 32
SeamInvocationContext.proceed() line: 56
RollbackInterceptor.aroundInvoke(InvocationContext) line: 28
SeamInvocationContext.proceed() line: 68
BijectionInterceptor.aroundInvoke(InvocationContext) line: 77
SeamInvocationContext.proceed() line: 68
ConversationInterceptor.aroundInvoke(InvocationContext) line: 65
SeamInvocationContext.proceed() line: 68
TransactionInterceptor$1.work() line: 97
TransactionInterceptor$1(Work<T>).workInTransaction() line: 61
TransactionInterceptor.aroundInvoke(InvocationContext) line: 91
SeamInvocationContext.proceed() line: 68
MethodContextInterceptor.aroundInvoke(InvocationContext) line: 44
SeamInvocationContext.proceed() line: 68
JavaBeanInterceptor(RootInterceptor).invoke(InvocationContext, EventType) line: 107
JavaBeanInterceptor.interceptInvocation(Method, Object[]) line: 185
JavaBeanInterceptor.invoke(Object, Method, Method, Object[]) line: 103