This project is read-only.

CODE framework project(s) as a module

Jun 6, 2014 at 8:23 AM
Hi,

We are using CODE for at least 9 months and happy with it.

And finally we have decided to use as a base framework for all our development requirements.

To satisfy different consumer request now we are developing applications, however we have many common Controller/view modules for each customer requirements. lets say we have modules M1, M2, M3 and M4 but the consumer C1 only requires M1 and M4 but C2 requires all of them.

So my question is how can call or use that functionality which was developed before using CODE MVC pattern, and consume that modules at runtime depends on in a newly developed MVC project (or add some conditions and continue considering that) considering consumer requirement(s)?

Best regards.
Emrah YILDIRIM
Jun 11, 2014 at 10:25 PM
Edited Jun 11, 2014 at 10:28 PM
Finally I found a solution;

The first problem is other module can not be resolved even the modules stays in the same directory with the executable file
so added a on App startup module finder and loader into AppDomain with AppDomain.Current.Load(assemblyName) method

Second even your module loaded successfully view finder in CODE.Framework was not able to resolve and load Page.XAML s successfully so I have made two modifications. the first in Controller.cs file;
        private bool FindView(string viewName, ViewLevel level, ViewResult result, List<string> locationsSearchedUnsuccessfully = null)
        {
            var foundView = false;
            var controllerType = GetType();
            var controllerName = GetType().Name.ToLower();
            if (controllerName.ToLower().EndsWith("controller"))
                controllerName = controllerName.Substring(0, controllerName.Length - 10);

            foreach (var engine in RegisteredViewEngines)
            {
                var viewResult = engine.GetView(viewName, controllerName);
                if (viewResult.FoundView == false)
                {
                    viewResult = engine.GetView(viewName, controllerType.Assembly.FullName+";"+controllerType.Name.ToLower());
                }
                if (viewResult.FoundView)
                {
                    result.View = viewResult.View;
                    result.ViewSource = viewResult.ViewSource;
                    result.ViewTitle = SimpleView.GetTitle(viewResult.View);
                    result.ViewIconResourceKey = SimpleView.GetIconResourceKey(viewResult.View);
                    result.View.DataContext = result.Model;
                    var haveViewInformation = result.Model as IHaveViewInformation;
                    if (haveViewInformation != null) haveViewInformation.AssociatedView = result.View;
                    result.ViewLevel = level;
                    foundView = true;
                    break;
                }
                if (locationsSearchedUnsuccessfully != null) locationsSearchedUnsuccessfully.AddRange(viewResult.LocationsSearched);
            }
            return foundView;
        }
in this method if the view found successfully no problem for that however if not found I am sending assembly full name and controller concat with ';' so in next step I can use it.
loose XAML's (Xamls content type page compiled with MSbuild:Compile) first searched and if found loaded auto with following pattern;
 var searchPath = "/views/" + controllerName + "/" + viewName + ".xaml";
However in our scenario it is always failed since our Controller and views located in another assembly to solve this I have added one more step after normal search and if it is fails it will try to use incoming data through the controller parameter and try to search and load desired view using following search pattern:
 searchPath = string.Format(@"/{0};component/{1}", assemblyParts[0], "views/" + asmAndController[1].Replace("controller", "") + "/" + viewName + ".xaml");
and full code for GetView as follows:
      public ViewEngineResult GetView(string viewName, string controllerName)
        {
            viewName = viewName.ToLower();

            var failureResult = new ViewEngineResult { FoundView = false };

            var searchPath = "/views/" + controllerName + "/" + viewName + ".xaml";
            var viewResult = TryGetView(searchPath);
            if (viewResult != null) return viewResult;
            if (controllerName.Contains(";") && controllerName.Contains("CODE.Framework.Wpf.Mvvm") == false)
            {
                string[] asmAndController = controllerName.Split(new char[] { ';' });
                if (asmAndController != null && asmAndController.Length > 1)
                {
                    string[] assemblyParts = asmAndController[0].Split(new char[] { ',' });
                    if (assemblyParts != null && assemblyParts.Length > 0 )
                    {
                        searchPath = string.Format(@"/{0};component/{1}", assemblyParts[0], "views/" + asmAndController[1].Replace("controller", "") + "/" + viewName + ".xaml");
                    }
                }
                viewResult = TryGetView(searchPath);
                if (viewResult != null) return viewResult;
            }
            failureResult.LocationsSearched.Add(searchPath);

            searchPath = "/views/shared/" + viewName + ".xaml";
            viewResult = TryGetView(searchPath);
            if (viewResult != null) return viewResult;
            failureResult.LocationsSearched.Add(searchPath);

            return failureResult;
        }
Of course after changing the above methods you have to recompile and link your existing code against newly compiled dll's

now your code framework app fully supports different module loading in the exe file.

However controller name should be unique I think.

Best regards.
Emrah
Jun 12, 2014 at 3:42 PM
Hello!

What exactly do you mean by "module"? You mean breaking the app into different DLLs or are you talking about reusing completely different "things" that aren't as such designed as CODE Framework? Or is the main concern only finding the views?


Markus
Jun 13, 2014 at 8:19 AM
Hi Markus,

by saying module I mean to use controller and views from another DLL. Load and consume whenever the app needs like Prism (or MEF) does (now it is loading all modules it founds under app. dir.).

And that changes I think it is not breaking any discipline introduced in CODE framework. aim to just to maximize code re-usability and minimize many other things like EXE file size, etc..

Now I managed that by using above introduced little code modification. Also CODE Controller and views discovery I think didn't get any disturbance from that modification however extended one more step!

And as an example, I have moved Login controller to another Class library project (or it can be another CODE Framework MVC/MVVM project should be compiled as class library) which is created with same directory structure used in CODE MVC/MVVM application, its models, controller and views moved into that DLL with copy/paste commands and calling it from the main application with same Controller.Action("User", "Login") syntax and working perfectly. Now as you may whenever I need changes on Login view or controller I do no need re-compile main EXE coordinator but the just login module.

I can also send you sample demo project if you want.

Best regards.
Emrah
Jun 14, 2014 at 1:02 AM
OK. Yes, that makes sense. I'll make sure the next build supports this.

Thanks for the input!


Markus
Nov 16, 2014 at 7:16 AM
Dear Markus,
I have downloaded the new release however our project totally crashed since now we are using above explained and both agreed pattern for loading external CODE modules. Did you changed your mind to adding that method additions or forget to add into new release?

Thank you best regards.
Emrah YILDIRIM.
Nov 18, 2014 at 9:56 AM
Hmmm... it should be included, but now I am not sure what happened. I will have to investigate.

Markus
Jan 12, 2015 at 2:12 PM
FYI: This is now in the next build for sure.

The actual implementation is slightly different. (In your example, view engines are kind of tricked into loading from separate assemblies, while in our implementation, the view-engines actually become aware of separate assemblies).

I will also write a short quick-top about how to use this feature.


Markus
Jan 12, 2015 at 2:44 PM
Jan 12, 2015 at 3:21 PM
Dear Markus,

That is great, however do we need to include component DLL file in EXE references or will it be simply enough to copy by somehow that DLL into MagazineManagement.EXE working folder?

Emrah.
Jan 12, 2015 at 3:26 PM
A reference needs to be added. In fact, this is by design. We didn't want to automatically pick up new DLLs just by copying them into a folder due to security concerns. However, you could probably write yourself a mechanism quite easily that uses a file watcher or something and whenever a new DLLs shows up, just call the ApplicationEx.Register... method.

Markus