DevExpress XAF is a framework for .NET and Visual Studio developers who wants to create Office-like LOB apps for desktop, web and mobile faster and without hiring a large team.
Недавно выступал на встрече GETDEV.NET c кратким обзором нашей технологии Domain Components (DC). Вот небольшая аннотация к докладу:
"Задумывались ли вы когда-нибудь, что с переходом от SQL к DataSet, а затем и к ORM типа Entity Framework развитие технологий для доступа и управления данными приостановилось? Что еще нового можно придумать к уже привычному оперированию записями таблиц БД как объектами CRL и при этом поднять удобство разработчика на следующий уровень? На этот и другие вопросы попробует дать ответ доклад о технологии Domain Components (часть DevExpress eXpressApp Framework), которая облегчает создание повторно используемых бизнес моделей за счет легкого комбинирования путем использования интерфейсов вместо классов (это позволяет вам эмулировать "множественное наследование" в C# и VB.NET), а также свободы от особенностей конкретной ORM."
So, I will use a similar approach in my XPO-based OData Service project (you can learn more on how to create it via the wizard here). Once I created the service, I will have to modify my XpoDataServiceV3 descendant as shown below:
1. I initialized the static serviceContext variable and provide the namespace of our auto-generated DC entities as the second parameter: "DevExpress.ExpressApp.DC.GeneratedClasses". It is important to avoid dealing with long-named entities like "DevExpress_ExpressApp_DC_GeneratedClasses_Survey" in our consumer applications.
2. I initialized the data layer that is used by my XpoContext descendant via the static CreateDataLayer method. There I used some XAF magic, which is required for DC, because domain logic methods accept the parameters of the IObjectSpace type. If I did not use DC, then I would not use the XAF classes in my data service and rather go using pure XPO stuff.
3. I overrode the GetSessionCore to use the Session created by the XAF's ObjectSpace, again for the correct work of domain logic methods. Take special note that this virtual method is available in version 12.2.8+ only (thanks to our XPO guys for implementing my request so quickly;-)). If you want to test it right away, I have included the latest version of the DevExpress.Xpo.v12.2.Extensions assembly into the demo project I posted here.
Finally, let me demonstrate why I created the OData service in the first place. Of course, I needed it for my mobile DXTREME application:
Originally when experimenting with this DC-based service I tried to reference the DcAssembly.dll into my data service project. This cache assembly is automatically generated by XAF when running the application with no debugger attached. So, to get it, I simply ran my XAF WinForms application, which used the same data model, and then copied the generated assembly from the Release/Bin folder into my data service project. Since this assembly contains regular persistent classes instead of DC interfaces (remember my recent talk about different types?), I hoped that this way it might be easier for you to understand and work with. Unfortunately, I had to stop using this undocumented approach later, because it required additional configuration from the application for the correct operation of the DC-based functionality: normally, when XAF loads this assembly internally it also calls the private void ProcessGeneratedAssembly(Assembly generatedAssembly) method of the XpoTypeInfoSource class. Another reason is that with the DcAssembly.dll approach it would also be more difficult to deploy and maintain the app due to the overhead on generating and copying the assembly...
If you are using Domain Components (DC), you may be already aware of the fact that XAF generates real business entities from registered DC interfaces at runtime. If you have a code that checks types of the current object (e.g., you want to do something only if the current object is of YourBusinessEntityType), you should take this important fact into account, otherwise it may lead to an error, which is quite easy to diagnose, though. A good example of this can be found in this Support Center ticket (which actually forced me to blog about this):
usingDevExpress.ExpressApp.DC; usingDevExpress.ExpressApp.Xpo; ... private void checkType_Execute(object sender, SimpleActionExecuteEventArgs e) { foreach (object current in View.SelectedObjects) { /* This is wrong, because real types are generated at runtime based on registered DCs. if (current.GetType() == typeof(DomainComponent1)) */ //The next three variants are good to go. //if (typeof(DomainComponent1).IsAssignableFrom(current.GetType())) //if (current.GetType() == ((IDCEntityStore)XafTypesInfo.PersistentEntityStore).GetGeneratedEntityType(typeof(DomainComponent1))) if (current.GetType() == XpoTypesInfoHelper.GetXpoTypeInfoSource().GetGeneratedEntityType(typeof(DomainComponent1))) DoSomethingUseful(); } } ...
As you can see, DC provides you with a method that returns the generated runtime type. Also, the type of the generated entity supports or implements DC interfaces used to form this entity, so you can use the System.Type.IsAssignableFrom method here. I hope you find this information helpful.
This solution enables you to save time by using Intellisense instead of typing logic methods names manually. Probably, this is also where CodeRush may help, but a common base class is still a brilliant solution, which I remember we used in the far far past (notice EntityService there).
If you are using DC, you are probably aware of the feature request we have regarding the new security system. We have implemented it in 12.2 and created a new demo for you:
"Starting from version 12.2, we will provide a DC-based demo that works with the new security system. For your convenience, both XPO and DC-based versions will be available as part of our SecurityDemo solution."
Note that as indicated and discussed with our customers in this thread, we did not consider scenarios with assigning permissions to shared parts, but rather to real entities only. This decision was made because it appears to be more logical as end-users can operate with registered entities only, and not with individual domain components that stay behind the scenes. In addition, this significantly decreases the complexity of the entire system and thus makes it more stable.