Proper way to Create/Update/Delete hierarchical data - c#

So I have a structure like this:
Widget:
Component 1:
Component 2:
Component 3:
...
Component n:
I'm building an ASP.NET MVC web app that as part of its functionality will allow a user to create a Widget object and assign Component objects (which have a number of properties) as "children" of the Widget object. Users might have no Components or might add 50. In addition, they may edit a Widget object and arbitrarily remove or change Component properties.
Everything in the application is working but I'm not happy with the way this is structured. On Submit currently, I submit all Components with ALL their properties. I delete all components currently associated with this Widget and then enumerate over each Component and re-add it.
...But I'm not happy with this solution. For some Widgets with a massive amount of components (say 500) this process can be time consuming even if the user only changed one component. But the alternative (tracking Creates/Updates/Deletes on a per Componenent basis) seems really painful to build.
I'm sure that I can do this better, so I'm interested in knowing what sort of patterns can be applied to solve this problem (generally speaking) and particular in the context of web applications.

Why is tracking the Create/Update/Delete so much harder? Take a look at my response to a similar question about finding the differences between what is in your repository and what is being posted back. Provided each Component has a unique ID (which it sounds like it does), it shouldn't be that difficult. Also it should be somewhat quicker for larger Widgets with lots of Components as you're not rebuilding its list every time.

Related

Blazor CascadingParameter vs singleton DependencyInjection

I have recently learned that you can provide cascadingValues to the entire project by wrapping the Router component in the provider Microsoft doc. How is this different to using dependency injection with a singleton pattern? (I know how injection works, I mean performance and architecture wise)
Which do you think is better to use?
There has been some discussion about the performance impact of CascadingValues. I can recommend this article (it is an excellent tutorial as well).
As you mentioned, there are two aspects: performance and architecture.
Performance
I'd see [CascadingParameter] are costly compared to [Parameter] or "normal" fields and properties. Each component down the tree, subscribe to the [CascadingParameter] changes. If the value changes, a new cycle of ParamtersSet is started, which could lead to a call to the render tree and check if something in DOM needs to be changed. So, even if no rerendering is required, the process to reach this conclusion consumes time. The more components, the more depth the tree has, the slower this process becomes.
Architecture
To discuss this aspect, we can think about the CascadingAuthenticationState. It is part of the authentication framework for Blazor and provides access to check whether a user is authenticated or not. It is implemented as a cascading value instead of a singleton. Components down the tree, like menus, can easily use this value to hide/show items for non authenticated users. Why?
Frequency of change and impact to the DOM
A question to answer is regarding the impact of the change of a cascading value. If a user logins/log out, it is reasonable to assume that this will trigger a huge DOM change. So, checking a huge part of the tree (if not the entire based on where the cascading value is placed) is not overhead.
Besides, it is a good guess that there will be few changes to AuthenticationState during the lifetime of the application.
Simplicity
The menu component uses the AuthorizeView which uses the cascading parameter of Task<AuthenticationState>.
<AuthorizeView>
<Authorized>
<li>Admin</li>
</Authorized>
<NotAuthorized>
<li>Log in</li>
</NotAuthorized>
</AuthorizeView>
This snippet is easy to read, and you can understand it very quickly. If you did the same thing with a singleton service, you would need to implement the "communication" between component and service. It would be best to implement a subscribe/unsubscribe scenario, maybe using events or more advanced technologies. You will need to write your own code, and again don't forget to write your implementation of IDisposable to unsubscribe.
Cascading parameters are focused on UI
While a singleton service is a very generic approach to solve many different issues, cascading values are specially designed to solve UI update problems. They are doing it very efficiently. In the case of the AuthenticationState, it uses a specialized view.
There is space for arguments if Blazor isn't all about UI, but with modern, rich features GUI, sometimes we have a layered approach inside the application. So, with UI, I mean the part of the application ultimately responsible for rendering.
Services could be used outside of this inner UI layer, through the entire application, and then reused in the UI as well, while cascading parameters could only be used inside components.
Cascading parameters are (mostly one way)
A cascading parameter is "owned" by a component. Usually, the component where it is declared. From that point, it is passed down the tree. All other components can consume it. There is no straightforward, easy, and scalable way to update a value from a child component. As I said, mostly, there are ways to do it, but it is a dirty path, in my view.
Summary
As with a lot of other technologies, the answer is: It depends on the use case.
top-down usage: cascading values
Components need to update the value: service
many changes: It highly depends on the tree structures if easiness outweighs the performance impact.
use outside and inside the inner UI layer: service
And, another approach to this problem could be something like Blazor Component Bus
Update
In addition to what was said by Just the benno, I may add that there is a fundamental difference between a CascadingValue component and a Singleton service regarding their scope. A Singleton service, in Blazor Server App, is singleton across the lifetime of the application, across multiple connections, and across multiple browsers... while CascadingValue component is scoped to the current instance of your app. Changing the state of an object provided by a CascadingValue component has no effect on a new instance of the app. But if you change the state of a Singleton service in an instance of your app, this change will be propagated to other instances of your app. Try to imagine what would be the implications of implementing the functionality of the CascadingAuthenticationState component as a Singleton service rather than CascadingValue.

Handling code of multiple ASP.NET websites based on the same template

I am using ASP.NET MVC and have to develop and deploy multiple websites based on a first website.
There are variation in some controllers, some views, some scripts and some models, and the Database are different on each website (mainly columns are differents but table names remains the same).
Is there a way to handle such a thing in a single Visual Studio Project, in order to make maintaining easier, and be able to add common feature easily on every website ?
Currently, I copy the pilote project into a new VS project, and change all the variation. But I find it's not an ideal situation (because of maintaining/improving).
I have implemented something like that years ago and can give some general advice you might find useful.
First of all developing app with such "multitenancy" has nothing to do with MVC pattern itself. You can do that without MVC :D. Second, if the websites supposed to work with different business domains I am afraid there is no generic way to do what you want. In my case it was just a number of e-commerce platforms.
Anyway, consider next things.
1.Think about using sub-domain approach if you can. It will free you from stupid routing and cookies shenanigans. Basically you can map *.yourdomain.com to one app and handle the necessary logic related to tenant easily. So in my case it was an application that behaved differently depending on provided url, not route, but sub-domain, 'superclient.yourdomain.com' for example. Its not always possible or good idea, but think about it.
2.Dependency Injection everywhere. Well, its useful in general but in your case is absolute must have - try abstract any tenant specific logic in separate types and init them in one place. Its everything related to localization, timezone settings, app theme, branding info on the app header etc. Just initialize and inject where its needed. If you have something like
if (website1) {
showBlockOne();
} else if (website2) {
showBlockTwo();
} else if (website3) {
showBlockThree();
}
then you doing something wrong, its a road to insanity. It should be something like
_currentTenantViewContext.ShowBlock();
So its polymorphism over conditional operators in most cases.
3.In my case the requirement was to create an app which can work with any language so I had to handle that issue on database side as well. The problem is that if usually you have lets say for example ProductType table in database with Id and Name, in multitenant application its not that simple. My solution was to create two tables - ProductType with Id and Code fields and ProductTypeLocalization table with Id, ProductTypeId, LanguageId, Value fields to handle this problem. Requirement also was to make this values editable from admin panel...
I don't know is it the case for you, but if yes think about it before the shit hits the fan in future.
4.For situations where you need some specific fields in some database table only for one site its not a good idea to spawn them freely (in general). Consider using some generic format for that, like JSON or XML. If you have few additional text fields for specific website in some table just create one field (call it ExtraSettings or something) and store this strings as JSON in that one field. Of course you have to handle this data in separate way, but its about dependency injection again.
Also you can use NoSQL for that.
5.Provide feature toggling, different websites requires different blocks to be displayed, rules applied etc. You have to have some way to on/off them for particular website(tenant) without recompile/redeploy.
Hope it helps.

Implementing a plug-in/templating system c#

I have a fairly simple console app that monitors an exchange mailbox, picks particular emails out, and updates a couple of databases based on the contents.
I would like to implement a couple of similar systems. While it would be very simple to duplicate this system, I am looking at a more sophisticated solution - mainly an intellectual exercise, a learning exercise.
I would like to build a core application that pulls template information periodically from a DB; this information would tell the app that is has to monitor a given mailbox for emails with given characteristics at a particular interval.
I envision creating a master template (assembly) with some virtual functions (pre-processing, process items, archive items, send notifications etc). In turn, I'd create any number of templates that implement the interfaces in the master template, but the functionality could differ wildly in each case, one may update a database, while the next might store something in a file system.
My first question is whether this is a sensible implementation?
My second question is how to dynamically reference each template, and how would I call the methods of these templates at the appropriate time?
If I were to extend my Templates project, adding a new class for each new template required, I'd overcome the problem of dynamically referencing the templates. But if I wanted to keep them in separate assemblies.. Is there a way to just drop them into the project? Don't forget, the templates will be listed in a DB, so the app will be aware of them, but how to make use of them...
UPDATE:
I've figured how I can dynamically reference each template class; it requires me to supply the Assembly-Qualified Name to GetType:
I've tried to dynamically generate the template in the main app:
string aqn= "MasterTemplates.TestTemplate, TestTemplate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
MasterTemplate mt = (MasterTemplate)Activator.CreateInstance(Type.GetType(aqn));
So if I keep updating my MasterTemplates project, adding in new classes as necessary, I can achieve what I am aiming for. However, how can I handle different template assemblies?
In the meantime, I'm shortly going to look at DBM's suggestion of the Managed Extensibility Framework.
Conclusion:
I don't have the time to fully investigate MEF; though it's overkill for my current needs, it looks extremely promising. And I haven't figured how to easily develop and use different assemblies for different templates - instead I am keeping all templates in one assembly, which I will have to recompile and up-date each time I require a new template. Not quite as sophisticated as the MEF alternative, but simpler and suited to my current needs.
You could use MEF to dynamically load plugins. It's in-the-box in VS2010, and works great for dynamically loading assemblies.
When using activator with a string, use the Activator.CreateInstance(String,String) overload.
Alternatively you can create an instance of the type and use it like that:
Activator.CreateInstance(Type.GetType(templateName));

Web Workflow Approach

I want to implement a workflow system on a new website which i am developing. Basically have
an order object (in future may have many more objects) which can have different statuses i.e. initial,assigned,dispatched,cancelled etc. It is the case that the order can only go from one status to another e.g can go from assigned to dispatched but cant go from initial to dispatched etc. i am hoping that maybe someone can give me an approach which is best to take for something like this??????
Try Windows Workflow Foundation, it might be overkill for your application.
If you your WF system is that simple and you do not expect it to evolve much, you could use regular objects with an enumerated type or a dictionary / list of statuses.
Type and value together will give you current status and a list of available actions. Persistence of WF objects will also be very easy.

MVP and presenter granularity

We've been using the MVP pattern and Winforms with a fair amount of success. However, a question always pops-up about MVP:
What is a good granularity for presenters?
What I mean by that is: With Winforms, a fine-granularity usually works quite well for user controls. That way, it's easy to reuse user controls and use them as building blocks while designing more complex GUIs. However, having the same (fine-)granularity with presenters seems to be a problem.
On one hand, having coarse-grained presenters hinders the ability to use "plug-in" controls and it sorts of violate the DRY principle: Multiple presenters often need to implement the same logic (populate a list of customers, for instance), which is used by multiple, more complex, controls.
On the other hand, fine-grained presenters seem to limit the ability to reuse controls in different situations. For instance, an editing view might sometimes need to save the customer right away; sometimes it needs to link it to something else; sometimes is just needs to validate it; and so on. It often depends on the more complex control. But there's also a fair amount of shared behaviour.
Note that, in both cases, 1-presenter-1-view is achievable. What is considered "1-view" changes.
What is usually considered best-practices for presenter granularity using MVP and Winforms?
Fine-grained presenters and customizable behaviour through options or something of that nature?
Coarse-grained presenters and low presenter reusability?
Something else?
Disclaimer: We mainly use Supervising Controller but I think it also applies to Passive View. Sorry for the long question, too.
We use MVP at all of our clients and this is definitely a conversation that comes up in more than one occasion. How clean should our code behind classes and presenters be? Having said that, we have chosen to use the coarse-grained presenter approach. Basically, every form would have its own presenter and would only get and set properties of any of the controls on a particular form using its view. Populating controls-a call to a db to populate a combobox for example-is located in a public service class. Any validation of user inputted data is located in a BO class which can be reused by any and/or all of the presenters. I hope this helps.
In my CAD-CAM system my presenters don't use user controls. User controls reside in the view which reside in a EXE assembly that implement the view interfaces the presenter use.
If want to display a list of customers I hand it off to the view which has a DisplayCustomerList and it uses whatever combination of user controls it needs to display the customer list. If multiple views show the customer list in the same way then in the ExE/View assembly they share a user control or class for doing that. That class doesn't go outside of that assembly.
Our software is adapted to run many different types of metal cutting machine. So we place a lot of emphasis on being able to rip off the UI and replace it with a completely different UI (corresponding to a different machine). All of these UIs reference the same set of core assemblies.
The hierarchy looks like this
View EXE
Presenter Implementation
Command Assembly - commands are executed by the presenter that modify the model
Presenter Interfaces
Model Assemblies
Off to the side are loadable assemblies that define dynamic content like what file types can be loaded, reports, cutting device drivers, etc. These implement various interfaces found in the model assemblies
One thing I do is that I don't impelment a view presenter for every dialog. If the dialog is tightly bound with a command then it is defined, created, and used along side the command class. Occasionally a group of related commands will share a dialog (File handling for example).
The essential question I ask when using MVP is "What happens if want to completely replace the forms with something else?". The answers to that question will identify where you are too dependent on a particular user control or form engine.
The biggest problem (and one that I haven't got a good answer for) of my setup is that current IDEs and langauges make it very easy to tie user controls to database records. It is so productive compared any other setup it tends to dominate the design. I haven't had to deal with the issue much in my CAD-CAM application so I don't have any answer other than passing the dataset to the view and let it handle it. This site has some patterns that may be of use in this situation.

Categories

Resources