[C#/WF4] Rehosted designer externe activities inladen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 11-09 18:27
Hallo allemaal,

Wij maken gebruik van Windows Workflow Foundation 4 in onze applicaties (WinForms). De eindgebruikers van onze applicaties hebben de mogelijkheid om zelf workflows aan te maken met de rehosted workflow designer. Deze designer is door middel van een ElementHost en een WPF UserControl op een WinForms form geplaatst.

Naast het maken van workflow kunnen eindgebruikers ook assemblies inladen als references zoals dit bijvoorbeeld ook in Visual Studio kan.
Met gewone .dll assemblies geeft dit geen problemen en de types binnen de dll kunnen ook in de workflow gebruikt worden. De assemblies worden opgeslagen in de database en tijdens het laden van de applicatie worden deze op schijf gezet in een tijdelijke map en ingeladen door middel van de Assembly.Load functie.

Naast gewone .dll assemblies willen we ook toestaan om Activity Libraries met daarin Workflow Activities in te laden en de Activities in deze assemblies toe te voegen aan de ToolBoxControl met activities. Hierin gaat het fout.

Zo gauw ik probeer de activities toe te voegen aan de ToolBoxControl krijg ik een FileNotFound exception. Ergens in de .Net code wordt geprobeerd de zojuist gekozen assemblies nogmaals in te laden, terwijl ik deze zelf al ingeladen heb door middel van Assembly.Load(). Ik heb er zelf al de types welke erven van Activity al uit opgehaald.

De code die ik nu heb is als volgt:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        public Assembly AddReference(string AssemblyFileName)
        {
            try
            {
                Assembly asm = Assembly.LoadFrom(AssemblyFileName);

                //Load the assembly
                AssemblyContextControlItem contextItem = _WorkflowDesigner.Context.Items.GetValue<AssemblyContextControlItem>();
                if (contextItem.ReferencedAssemblyNames == null)
                {
                    contextItem.ReferencedAssemblyNames = new List<AssemblyName>();
                }
                contextItem.ReferencedAssemblyNames.Add(asm.GetName());
                _WorkflowDesigner.Context.Items.SetValue(contextItem);

                var root = GetRootElement();
                var fullname = asm.FullName;
                if (null == root)
                {
                    return null;
                }
                VisualBasicSettings vbs = VisualBasic.GetSettings(root) ?? new VisualBasicSettings();

                var namespaces = (from type in asm.GetTypes() select type.Namespace).Distinct();
                foreach (var name in namespaces)
                {
                    var import = new VisualBasicImportReference() { Assembly = fullname, Import = name };
                    vbs.ImportReferences.Add(import);
                }
                VisualBasic.SetSettings(root, vbs);
                
                List<Type> activities = GetActivitiesFromAssembly(asm);

                if (activities != null && activities.Count > 0)
                {
                    AddCategoryToToolbox(_ToolboxControl, asm.GetName().Name, activities);
                }

                _ReferencedAssemblies.Add(asm.GetName().Name, asm);

                return asm;
            }
            catch (Exception)
            {
                return null;
            }
        }

        private void AddCategoryToToolbox(ToolboxControl tb, string Category, List<Type> activities)
        {
            var builder = new AttributeTableBuilder();
            ToolboxCategory cat = CreateToolboxCategory(Category, activities, true, builder);
            MetadataStore.AddAttributeTable(builder.CreateTable());
            tb.Categories.Add(cat);
        }


Aan de ene kant begrijp ik de exception wel, het framework probeert de dll te zoeken maar kan deze niet vinden omdat die buiten de zoekplaatsen zich bevindt, maar de dll is al ingeladen dus er hoeft eigenlijk helemaal niet gezocht te worden.

Weet iemand misschien hoe dit op te lossen is?

Hail to the king baby!


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10-09 20:32
De dll kopieren naar een directory waarin het framework gaat zoeken?

Je zou met assembly probing settings in je config file een aparte directory aan kunnen wijzen waar gezocht moet worden naar referenties voor je app. Als je dan daar je externe dll's neerzet dan zou je al meer kans kunnen hebben..

Acties:
  • 0 Henk 'm!

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 11-09 18:27
Op dit moment heb ik het zo gemaakt dat de assemblies die gekozen worden gekopieerd worden naar een map in het profiel van de gebruiker. Voor zover ik heb kunnen vinden is het niet mogelijk om private probing paths op te geven die buiten de map van de applicatie ligt.

Dus dat zou al een lastige optie worden, ik ben ook meer benieuwd waarom het ToolboxControl denkt dat de assembly nog geladen moet worden, deze is namelijk al geladen!

Hail to the king baby!


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Tsja, dit is wat lastig reproduceren natuurlijk. :p Met zoeken is de eerste hit:
The FileNotFoundException can be raised even when the assembly does exist if one of the dependent assemblies couldn't be loaded.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 11-09 18:27
pedorus schreef op donderdag 01 december 2011 @ 22:28:
Tsja, dit is wat lastig reproduceren natuurlijk. :p Met zoeken is de eerste hit:

[...]
Hmm, dat is niet echt mijn probleem. Daar wordt de assembly helemaal niet geladen, ik heb hem al geladen zonder exception. Alleen het toevoegen aan het toolboxcontrol geeft die exception. Een assembly met alleen System references geeft de fout ook.

Hail to the king baby!


Acties:
  • 0 Henk 'm!

  • eek
  • Registratie: Februari 2001
  • Laatst online: 06-04-2020

eek

@MagickNET

Zou het kunnen zijn dat je de assemblies die door de dll gereferenced worden ook moet toevoegen aan: "contextItem.ReferencedAssemblyNames"?

Skill is when luck becomes a habit.


Acties:
  • 0 Henk 'm!

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 11-09 18:27
Top tip! Ik heb het event geimplementeerd, als het geraised wordt kijk ik gewoon in de lijst met ingeladen assemblies of deze al voorkomt. Zo ja dan geef ik die terug. Werkt als een trein.

De code ziet er dan zo uit:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    Assembly[] AssembliesLoaded = AppDomain.CurrentDomain.GetAssemblies();

    foreach (Assembly MyAssembly in AssembliesLoaded)
    {
        if (MyAssembly.FullName == args.Name)
        {
            return MyAssembly;
        }
    }

    return null;            
}

[ Voor 9% gewijzigd door urk_forever op 02-12-2011 10:58 ]

Hail to the king baby!

Pagina: 1