how to use asp.net dynamic data with Entity framework in another dll - asp.net

how can i use asp.net dynamic data using EF in another dll and i dont want to put connection string in web.config or any config file.
I have this code in Global.asax
model.RegisterContext(() => new MyObjectContext("entityconnectionString"), new ContextConfiguration() { ScaffoldAllTables = true });
the defalut page is ok but when i click on any table to see the details, I get this error:
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
How can i solve this problem?

I was able to resolve this by forcing the load of the MetadataWorkspace and use an overload of the RegisterContext().
var context = new MyEntities(); // DataContext
context.MetadataWorkspace.LoadFromAssembly(typeof(MyEntity).Assembly); // An EF Entity
var config = new ContextConfiguration() {ScaffoldAllTables = true};
DefaultModel.RegisterContext(() => context, config);

I'm having the same problem. I have my EDMX data model file in one project called NW.DataModel. I added the code generation item for POCO objects, which I then moved off to a separate project called NW.Entities, so that they could be persistence ignorant. I have to tweak a few property settings for namespace generation in the Context object so that the Context would recognize the entities when building the solution. This was all fine, and I can use these projects in Console apps and a WCFdata service. Now I want to add a dynamic data site for some basic admin, and that's when the separate assemblies no longer play together. I'm just testing the project settings with the Northwind database.
I get this error: Could not find the CLR type for 'NWEntities.Shipper'.
This blog post seems to have some ideas, and links to forums where the issue has some recent activity, but no word from Microsoft yet.
http://thedatafarm.com/blog/data-access/wcf-data-services-and-ef-pocos-that-are-in-their-own-assembly/

Jeff's answer just about works for me, but I kept getting ObjectDisposed Exceptions every now and then.
I've changed the context factory to create a new context, which seems to work:
var config = new ContextConfiguration() { ScaffoldAllTables = true };
DefaultModel.RegisterContext(() =>
{
var context = new MyEntities(); // ObjectContext
context.MetadataWorkspace.LoadFromAssembly(typeof(AnyPOCOInOtherAssembly).Assembly);
return context;
},
config);

Related

ASP.NET Core Identity - UserManager and UserStore woes

I'm trying to implement the Identity system in an ASP.NET Core app (RC2 libraries) and there is a particular hangup that is driving me crazy.
First of all, I am not using EntityFramework. I'm not even using SQL. I'm backing up to RavenDB, so I need the implementation to be very specific to that; Which isn't a problem.
So I designed a RavenUserStore class, and it looks like this;
public class RavenUserStore<TUser> :
IUserStore<TUser>,
IUserLoginStore<TUser>,
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserClaimStore<TUser>,
IUserLockoutStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserEmailStore<TUser> {
// ...
}
Works great on its own. I've implemented all the methods, etc. It's wonderful. Very clean and efficient.
Now, I go over to my web application and wire things up;
services.AddTransient<ILookupNormalizer>(s => new LowerInvariantLookupNormalizer());
services.AddTransient<IPasswordHasher<Member>>(s => new PasswordHasher<Member>());
services.AddTransient<IUserStore<Member>, RavenUserStore<Member>>();
services.AddIdentity<Member, Role>(o => {
o.Password.RequiredLength = 6;
o.Password.RequireDigit = true;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
})
.AddUserStore<RavenUserStore<Member>>()
.AddRoleStore<RavenRoleStore<Role>>();
So I go make a controller to use this, per all the samples I've seen, and the very core sample from the Identity Framework Github Repository
//... [PROPERTIES]...//
public AccountController(UserManager<Member> userManager, SignInManager<Member> signInManager) {
// ... [attach constructor parameters to properties] ...//
}
Alright, so I inspect the classes carefully.
UserManager<T> has a property Store,which is a type of IUserStore<T>.
So theoretically.. if the dependency injection resolves types of IUserStore<T> to RavenUserStore<T> when they are injected through a constructor.. shouldn't that mean that the UserManager<T> gets a RavenUserStore<T> as its Store property?
I thought it would too; But when I call methods on the UserManager, it DOES NOT call the ones on my RavenUserStore. Why is this? What can I do?
Do I really have to ALSO make a custom UserManager class and do all of those methods AGAIN?
You need to add your own custom providers before calling services.AddIdentity(). Internally, AddIdentity uses TryAddScoped() which only adds the default items if they don't already exist in the services container.
So just putting the call to AddIdentity() after you registered all your custom implementations should mean that they will take precedence as you expect.

Dispose DbContext not dispose the ObjectContext entities

I'm using EF 5.0 to create a web and I have some issues disposing my context. All the times that I use a context is inside a using sentence, so the context should be disposed automatically but in a specific moment I get the next error when I try to attach an entity to a context:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
It semms that the entity is not disposed. How is the way to manage this situation? Do I have to dispose the ObjectContext to dispose the entities or is there any way to check if the Entity is attached?
Regards.
One way to do it is to detach the existing object before attaching. I don't have VS in front of me so I apologize if the code isn't exactly correct.
var existingObject = dbContext.Users.Local
.FirstOrDefault(x => x.id = newObject.id);
if (existingObject != null)
{
// remove object from local cache
dbContext.Entry(existingObject).State = EntityState.Detached;
}
dbContext.Users.Attach(newObject);
In case this doesn't fix the problem, you'll have to go to the old way of detaching objects.
// remove object from local cache
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
objectContext.Detach(existingObject);
If you do something like that:
User u;
using (Entities ent = new Entities())
{
u = ent.Users.Single(a => a.ID == 123);
}
using (Entities ent2 = new Entities())
{
//loading the same user
User user2 = ent2.Users.Single(a => a.ID == 123);
//trying to attach the same object with the same key
ent2.Attach(u);
}
then you will get this error (I haven't tested this code).
EDIT: one of the solutions is to change the object's state:
ent2.Attach(u);
ent2.ObjectStateManager.ChangeObjectState(u, EntityState.Modified);
another solution is to check if the entity is already attached:
ObjectStateEntry state = null;
if(!ent2.ObjectStateManager.TryGetObjectStateEntry(((IEntityWithKey)u).EntityKey, out state))
{
ent2.Attach(u);
}
Dispose doesn't mean "reset to factory settings". It is a way to clean up unmanaged resources like database connections and such.
The problem has nothing to do with disposing a context or not. It even has nothing to do with having multiple contexts somewhere in place. If this would be the problem you would get the "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" exception which is totally different to your exception.
You can simulate your exception quite easily with only a single context:
using (var ctx = new MyContext())
{
var customer1 = new Customer { Id = 1 };
var customer2 = new Customer { Id = 1 }; // a second object with the same key
ctx.Customer.Attach(customer1);
ctx.Customer.Attach(customer2); // your exception will occur here
}
The problem causing this exception is normally more hidden, expecially if you keep in mind that attaching or setting a state (for example to Modified) will also attach all related entities in the object graph of the entity you are attaching. If in this graph are two objects with the same key you'll get the exception as well, although you didn't attach those related entities explicitly.
But it's impossible to find the exact reason without more details about your code.

Event not working

I am new to Tridion Event System. I have written a small code.
[TcmExtension("MyEventHandlerExtension")]
public class EH : TcmExtension
{
public EH()
{
Subscribe();
}
public void Subscribe()
{
//EventSystem.Subscribe<Component, DeleteEventArgs>(HandlerForInitiated, EventPhases.Initiated);
EventSystem.Subscribe<Tridion.ContentManager.CommunicationManagement.Page, Tridion.ContentManager.Extensibility.Events.PublishOrUnPublishEventArgs>(HandlerForCommitted, EventPhases.All);
}
private void HandlerForCommitted(IdentifiableObject subject, PublishOrUnPublishEventArgs args, EventPhases phase)
{
TDSE obj = new TDSE();
Tridion.ContentManager.Interop.TDS.Publication pub = obj.GetPublication("tcm:0-150-1");
Tridion.ContentManager.Interop.TDS.Page pubPage = obj.GetPage("tcm:150-12374-64", pub);
pubPage.Publish("tcm:0-1-65538", false, true, false, default(DateTime), default(DateTime), default(DateTime));
}
}
using this code i wanted to publish a page everytime when a publish and unpublish event occur.
I build this code and register its path in tridion config file .
But its not working.Please Help
Ok, first of all remove all your TDSE code, you should use TOM.NET. You can get session as subject.Session
Then make sure you have registered this extension in Tridion.ContentManager.config and restarted your system
And finally - if something doesn't work, just add simple code that will create a file in your HandlerForCommitted whenever event occurs, this way you will be able to see if your extension get executed.
The 2011 Event System uses the TOM.NET API and not the TOM API. Please do not create new TDSE objects in the 2011 Event System. Even though you can reference the old Interop libraries, there is no reason to do so with 2011. Using the TOM.NET libraries you should see better performance and also the code is future-proof.
Mihai Cadariu has a nice example where he uses TOM.NET to Publish a page from a Tridion Template. Adjusting the code to check for previewmode or publish mode and setting your own user and priority (instead of reading it from the current transaction) should work well.
Below code from http://yatb.mitza.net/2012/05/publishing-from-template-code-using.html
public void Publish(Engine engine, String tcmUri, User user, PublishPriority priority)
{
Session session = new Session(user.Title);
PublishInstruction publishInstruction = new PublishInstruction(session);
RenderInstruction renderInstruction = new RenderInstruction(session);
renderInstruction.RenderMode = RenderMode.Publish; // work around. needs to be specified for binaries.
publishInstruction.RenderInstruction = renderInstruction;
List<IdentifiableObject> items = new List<IdentifiableObject>() { session.GetObject(tcmUri) };
List<PublicationTarget> targets = new List<PublicationTarget>() { engine.PublishingContext.PublicationTarget };
PublishEngine.Publish(items, publishInstruction, targets, priority);
session.Dispose();
}
// called with
PublishTransaction currentTransaction = TemplateUtils.GetPublishTransaction(engine);
TemplateUtils.Publish(engine, itemUri, currentTransaction.Creator, currentTransaction.Priority);
Your code seems to have the three things I "normally" forget:
the class is public
it extends TcmExtension
it has a TcmExtension attribute
If you've registered the class correctly in the configuration file, it should just be a matter of restarting the relevant module(s). In this case I'd expect those to be the Publisher and TcmServiceHost services.
After restarting those modules and triggering a publish action, you should see an event being logged (in the Windows event viewer) that your extension is being loaded.
If that even shows, it means your assembly is being loaded into the relevant Tridion process and the class is being recognized and instantiated.
If at this stage your handler doesn't fire you may have to consider listening to a different event. Whenever I want to interact with the publishing, I end up listening for the SaveEventArgs of a PublishTransaction, instead of the PublishOrUnPublishEventArgs on the Page.

Read AssemblyTitle attribute in ASP.NET

I use code below to read AssemblyTitle attribute of .NET apps, unfortunately Assembly.GetEntryAssembly() always return Null in ASP.NET app. How to read AssemblyTitle in ASP.NET app?
public static string Title
{
get
{
var attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
var titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title.Length > 0)
return titleAttribute.Title;
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().CodeBase);
}
}
You must have a type that you know is defined in the same assembly that contains the AssemblyTitle. Then you can do:
typeof(MyType).Assembly.GetCustomAttributes
Note that (for what I know) there isn't any other bulletproof method.
For example using HttpContext.Current doesn't work if you want to do it not during a web request (so you can do it on response of a user action, but not from a separate thread, or from a static initializer, or from global.asax)
Some similar readings (full of half successes):
GetEntryAssembly for web applications
Using the Web Application version number from an assembly (ASP.NET/C#)
I use the following in asp.net web app:
if (ApplicationDeployment.IsNetworkDeployed)
return ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
Edit: Sorry, thats just the version, not the title! I combined your version and mine:
System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
That gets the assembly title attribute just fine. The difference is in GetExecutingAssembly() versus your GetEntryAssembly().

Entity Framework reverting changes

I am develloping a web form that has a wizard with 4 steps:
On each step I'me creating new entities generated from a database.
The problem is that being a wizzard, the user can change the properties of the controls that will originate the values to be stored.
So I need to release the created entity objects or return that entity values to the original rows stored on the database.
How can I do this.
Should'n it work if I set each created entity object to null?
By the way this is how I'm doing it:
entities = new Entities();
...
Client client = new Client();
client.name = tbxName.text
...
entities.SaveChanges();
entities.Connection.Close();
So If this code is executed on the 2nd wizard part of a wizard of 3 parts and I go back and fowrward through this set more the once the client creating runs more than once, so there's my problem.
So how can I unCreate it :-P
Thannks!!!
If you are building wizard you must manage it as single operation. It means that you have to store built entity graph in the session and save it only if whole wizard is completed and confirmed. Your step logic also must check if related data are already present in the entity graph and use them instead of creating new one.
If your using Entity Framework, why not implement the Unit Of Work pattern? Each part of your wizard builds the UoW and the "final step" commits the unit of work.
There was an article called "The Unit Of Work Pattern And Persistence Ignorance" in MSDN magazine a few years ago that explains the concept.
This is the way I do it:
1- Create a place where you can manage your Session variables :
public class SessionObjects { }
2- I save my ObjectContext in the Session so I create a property to manage it in the mentioned class :
public static ObjectContextEntities ObjectContextEntities
{
get
{
return (ObjectContextEntities)HttpContext.Current.Session["ObjectContextEntities"];
}
set
{
HttpContext.Current.Session["ObjectContextEntities"] = value;
}
}
3- Initialize the ObjectContext on the wizard's start and dispose it on its end:
void StartWizard()
{
SessionObject.ObjectContextEntities = new ObjectContextEntities();
}
void StartWizard()
{
SessionObject.ObjectContextEntities = new ObjectContextEntities();
}
void EndWizard()
{
((ObjectContextEntities)SessionObject.ObjectContextEntities).Dispose();
}
4- To save wizard result to the database you can call:
void SaveWizard()
{
((ObjectContextEntities)SessionObject.ObjectContextEntities).SaveAllChanges();
}
5- To reset wizard simply call EndWizard then StartWizard .
I guess you know how to manage your ObjectEntity objects and in the ObjectContext so you can continue from here by your self ..

Resources