IoC.Configuration

IoC.Configuration is a container agnostic configuration of dependency injection.

IoC.Configuration is a wrapper around popular IoC containers, with additional functionality (see below). Currently Ninject and Autofac are supported through the usage of Nuget extension packages IoC.Configuration.Ninject and IoC.Configuration.Autofac.

Among other things, it allows:
  • Specifying dependency injection configuration in XML configuration file, as well as in IoC.Configuration module classes, or third party IoC container modules (e.g., Autofac or Ninject modules).
  • Easy switching between containers to use for service resolution (e.g., Autofac, Ninject).

In addition, the configuration file has sections for settings, plugins, startup actions, dynamically generated implementations of interfaces (see Autogenerated Services), etc.

All these functionality will be explained in corresponding sections, however here is a quick overview:

  • The dependency injection bindings are done using any combination of the following techniques:

    • In IoC.Configuration module classes using chained methods, pretty similar to how it is done in popular containers, Ninject and Autofac.

      Note

      The IoC.Configuration module classes should either implement IoC.Configuration.DiContainer.IDiModule, or extend the class IoC.Configuration.DiContainer.ModuleAbstr, and override the method Load().

    • In module classes of one of popular IoC packages (such as Autofac or Ninject). These modules will be referred as native modules.

    • In XML configuration file. This method is the preferred way to configure the dependency injection, since it is the most flexible. XML configuration files have sections for type bindings, as well as sections for IoC.Configuration or native (i.e., Autofac, Ninject, etc) modules.

    Note

    IoC.Configuration has its own syntax for type bindings, which reminds the syntax used in Ninject. However, IoC.Configuration translates these type bindings into 3-rd party IoC container (e.g., Autofac, Ninject, etc) bindings .

  • Type resolutions are done using one of popular IoC containers (e.g., Autofac, Ninject, etc), through the usage of implementations of IoC.Configuration.DiContainer.IDiManager interface.

    Note

    Currently, two implementations of IoC.Configuration.DiContainer.IDiManager are availabe, Ninject and Autofac implementations). These implementations are in packages IoC.Configuration.Ninject and IoC.Configuration.Autofac.

  • The container (e.g., Autofac, Ninject) used by IoC.Configuration can be switched in XML configuration file. Here is an exert from IoCConfiguration_Overview.xml, that shows the usage of element diManagers to specify container for resolving types:

<!--
The value of type attribute should be a type that implements
IoC.Configuration.DiContainer.IDiManager
-->
<diManagers activeDiManagerName="Autofac">
    <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
               assembly="ninject_ext">
        <!--
        Use parameters element to specify constructor parameters,
        if the type specified in 'type' attribute has non-default constructor.
        -->
        <!--<parameters>
        </parameters>-->
    </diManager>
    <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
               assembly="autofac_ext">
    </diManager>
</diManagers>

Sample Files

  • The XML configuration file schema is available at IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

  • A template XML configuration file can be downloaded from IoC.Configuration.Template.xml.

    Note

    The template file and schema are also available in folder, where Nuget package IoC.Cnfiguration is unpacked.

  • The XML configuration files listed below are used in some examples throughout the documentation. The file IoCConfiguration_Overview.xml provides an overview of various features of IoC.Configuration, while the other configuration files (e.g., IoCConfiguration_collection.xml, IoCConfiguration_constructedValue.xml), provide additional examples for some features.

    Note

    These configuration files can be found in test project IoC.Configuration.Tests. Most of type names in configuration files are meaningless (e.g., Interface1, Class1, etc)

XML Configuration File Schema

XML Configuration file is validated against the schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd below, when the file is loaded by IoC.Configuration.

This file can be found also in folder “IoC.Configuration.Content”, under the folder where Nuget package IoC.Configuration is downloaded (see the screenshot below), or can also be downloaded from IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or from oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

_images/ioc.configuration-files.jpg

To use Visual Studio code completion based on this schema, right click “Properties” on the XML configuration file, and select the schema in “Schemas” text box in properties tab (see the screenshot below).

_images/selecting-schema-in-vs.jpg

Alternatively, reference the schema in xmlConfiguration element as displayed below:

1
2
3
4
5
<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">
     <!--...-->
<iocConfiguration>

XML configuration file schema:

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
                xmlns:xs="http://www.w3.org/2001/XMLSchema">
     <xs:simpleType name="scopeValues">
             <xs:restriction base="xs:string">
                     <!--The same object will be used for all service resolutions -->
                     <xs:enumeration value="singleton"/>

                     <!--New object will be created per request-->
                     <xs:enumeration value="transient"/>

                     <!--The same object will be created per scope lifetime., however different objects will be created in different lifetime scopes.-->
                     <xs:enumeration value="scopeLifetime"/>
             </xs:restriction>
     </xs:simpleType>

     <xs:simpleType name="collectionTypes">
             <xs:restriction base="xs:string">
                     <xs:enumeration value="enumerable"/>
                     <xs:enumeration value="list"/>
                     <xs:enumeration value="readOnlyList"/>
                     <xs:enumeration value="array"/>
             </xs:restriction>
     </xs:simpleType>

     <xs:simpleType name="DateTimeType">
             <xs:restriction base="xs:string">
                     <xs:pattern
                                     value="[0-9]{4}-(0[1-9]|1(0|1|2))-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]).([0-9]{3})"/>
             </xs:restriction>
     </xs:simpleType>

     <xs:complexType name="doubleType">
             <xs:attribute name="value" use="required" type="xs:double"/>
     </xs:complexType>

     <xs:complexType name="namedDoubleType">
             <xs:complexContent>
                     <xs:extension base="doubleType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="byteType">
             <xs:attribute name="value" use="required" type="xs:byte"/>
     </xs:complexType>

     <xs:complexType name="namedByteType">
             <xs:complexContent>
                     <xs:extension base="byteType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="int16Type">
             <xs:attribute name="value" use="required" type="xs:short"/>
     </xs:complexType>

     <xs:complexType name="namedInt16Type">
             <xs:complexContent>
                     <xs:extension base="int16Type">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="int32Type">
             <xs:attribute name="value" use="required" type="xs:int"/>
     </xs:complexType>

     <xs:complexType name="namedInt32Type">
             <xs:complexContent>
                     <xs:extension base="int32Type">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="int64Type">
             <xs:attribute name="value" use="required" type="xs:long"/>
     </xs:complexType>

     <xs:complexType name="namedInt64Type">
             <xs:complexContent>
                     <xs:extension base="int64Type">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="booleanType">
             <xs:attribute name="value" use="required" type="xs:boolean"/>
     </xs:complexType>

     <xs:complexType name="namedBooleanType">
             <xs:complexContent>
                     <xs:extension base="booleanType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="datetimeType">
             <xs:attribute name="value" use="required" type="DateTimeType"/>
     </xs:complexType>

     <xs:complexType name="namedDatetimeType">
             <xs:complexContent>
                     <xs:extension base="datetimeType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="stringType">
             <xs:attribute name="value" use="required" type="xs:string"/>
     </xs:complexType>

     <xs:complexType name="namedStringType">
             <xs:complexContent>
                     <xs:extension base="stringType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="settingValueType">
             <xs:attribute name="settingName" use="required" type="xs:string"/>
     </xs:complexType>

     <xs:complexType name="namedSettingValueType">
             <xs:complexContent>
                     <xs:extension base="settingValueType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="objectType">
             <xs:attribute name="type" use="optional" type="xs:string"/>
             <xs:attribute name="assembly" use="optional" type="xs:string"/>
             <xs:attribute name="typeRef" use="optional" type="xs:string"/>
             <xs:attribute name="value" use="required" type="xs:string"/>
     </xs:complexType>

     <xs:complexType name="namedObjectType">
             <xs:complexContent>
                     <xs:extension base="objectType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="classMemberType">
             <xs:sequence>
                     <xs:element name="parameters" type="namedValuesType" minOccurs="0" maxOccurs="1"/>
             </xs:sequence>
             <xs:attribute name="class" use="optional" type="xs:string"/>
             <xs:attribute name="assembly" use="optional" type="xs:string"/>
             <xs:attribute name="classRef" use="optional" type="xs:string"/>
             <xs:attribute name="memberName" use="required" type="xs:string"/>
     </xs:complexType>

     <xs:complexType name="namedClassMemberType">
             <xs:complexContent>
                     <xs:extension base="classMemberType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="classMemberTypeWithDi">
             <xs:sequence>
                     <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
             </xs:sequence>
             <xs:attribute name="class" use="optional" type="xs:string"/>
             <xs:attribute name="assembly" use="optional" type="xs:string"/>
             <xs:attribute name="classRef" use="optional" type="xs:string"/>
             <xs:attribute name="memberName" use="required" type="xs:string"/>
     </xs:complexType>

     <xs:complexType name="namedClassMemberTypeWithDi">
             <xs:complexContent>
                     <xs:extension base="classMemberTypeWithDi">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="injectedObjectType">
             <xs:attribute name="type" type="xs:string" use="optional"/>
             <xs:attribute name="assembly" type="xs:string" use="optional"/>
             <xs:attribute name="typeRef" type="xs:string" use="optional"/>
     </xs:complexType>

     <xs:complexType name="namedInjectedObjectType">
             <xs:complexContent>
                     <xs:extension base="injectedObjectType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="parameterValueType">
             <xs:attribute name="paramName" use="required" type="xs:string"/>
     </xs:complexType>

     <xs:complexType name="namedParameterValueType">
             <xs:complexContent>
                     <xs:extension base="parameterValueType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="constructedValueType">
             <xs:sequence>
                     <xs:element name="parameters" type="namedValuesType" minOccurs="0" maxOccurs="1"/>
                     <xs:element name="injectedProperties" type="namedValuesType" minOccurs="0" maxOccurs="1"/>
             </xs:sequence>
             <xs:attribute name="type" type="xs:string" use="optional"/>
             <xs:attribute name="assembly" type="xs:string" use="optional"/>
             <xs:attribute name="typeRef" type="xs:string" use="optional"/>
     </xs:complexType>

     <xs:complexType name="namedConstructedValueType">
             <xs:complexContent>
                     <xs:extension base="constructedValueType">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="constructedValueTypeWithDi">
             <xs:sequence>
                     <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                     <xs:element name="injectedProperties" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
             </xs:sequence>
             <xs:attribute name="type" type="xs:string" use="optional"/>
             <xs:attribute name="assembly" type="xs:string" use="optional"/>
             <xs:attribute name="typeRef" type="xs:string" use="optional"/>
     </xs:complexType>

     <xs:complexType name="namedConstructedValueTypeWithDi">
             <xs:complexContent>
                     <xs:extension base="constructedValueTypeWithDi">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="collectionType">
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                     <xs:choice>
                             <xs:element name="byte" type="byteType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int16" type="int16Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int32" type="int32Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int64" type="int64Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="double" type="doubleType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="boolean" type="booleanType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="datetime" type="datetimeType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="string" type="stringType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="object" type="objectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="classMember" type="classMemberType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="constructedValueType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="collection" type="collectionType" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:complexType name="namedCollectionType">
             <xs:complexContent>
                     <xs:extension base="collectionType">
                             <xs:attribute name="name" type="xs:string" use="required"/>
                             <xs:attribute name="collectionType" type="collectionTypes" use="required"/>
                             <xs:attribute name="itemType" type="xs:string" use="optional"/>
                             <xs:attribute name="itemTypeRef" type="xs:string" use="optional"/>
                             <xs:attribute name="itemTypeAssembly" type="xs:string" use="optional"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="collectionTypeWithDi">
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                     <xs:choice>
                             <xs:element name="byte" type="byteType"/>
                             <xs:element name="int16" type="int16Type"/>
                             <xs:element name="int32" type="int32Type"/>
                             <xs:element name="int64" type="int64Type"/>
                             <xs:element name="double" type="doubleType"/>
                             <xs:element name="boolean" type="booleanType"/>
                             <xs:element name="datetime" type="datetimeType"/>
                             <xs:element name="string" type="stringType"/>
                             <xs:element name="object" type="objectType"/>
                             <xs:element name="classMember" type="classMemberTypeWithDi"/>
                             <xs:element name="settingValue" type="settingValueType"/>
                             <xs:element name="constructedValue" type="constructedValueTypeWithDi"/>
                             <xs:element name="injectedObject" type="injectedObjectType"/>
                             <xs:element name="collection" type="collectionTypeWithDi"/>
                             <xs:element name="parameterValue" type="parameterValueType"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:complexType name="namedCollectionTypeWithDi">
             <xs:complexContent>
                     <xs:extension base="collectionTypeWithDi">
                             <xs:attribute name="name" use="required" type="xs:string"/>
                             <xs:attribute name="collectionType" type="collectionTypes" use="required"/>
                             <xs:attribute name="itemType" type="xs:string" use="optional"/>
                             <xs:attribute name="itemTypeRef" type="xs:string" use="optional"/>
                             <xs:attribute name="itemTypeAssembly" type="xs:string" use="optional"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:complexType name="defaultValuesType">
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                     <xs:choice>
                             <xs:element name="byte" type="namedByteType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int16" type="namedInt16Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int32" type="namedInt32Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int64" type="namedInt64Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="double" type="namedDoubleType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="boolean" type="namedBooleanType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="datetime" type="namedDatetimeType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="string" type="namedStringType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="namedConstructedValueType" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:complexType name="namedValuesType">
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                     <xs:choice>
                             <xs:element name="byte" type="namedByteType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int16" type="namedInt16Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int32" type="namedInt32Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int64" type="namedInt64Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="double" type="namedDoubleType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="boolean" type="namedBooleanType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="datetime" type="namedDatetimeType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="string" type="namedStringType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="object" type="namedObjectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="namedConstructedValueType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="collection" type="namedCollectionType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="classMember" type="namedClassMemberType" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:complexType name="settingValuesType">
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                     <xs:choice>
                             <xs:element name="byte" type="namedByteType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int16" type="namedInt16Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int32" type="namedInt32Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int64" type="namedInt64Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="double" type="namedDoubleType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="boolean" type="namedBooleanType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="datetime" type="namedDatetimeType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="string" type="namedStringType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="object" type="namedObjectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="namedConstructedValueType" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:complexType name="namedValuesTypeWithDi">
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                     <xs:choice>
                             <xs:element name="byte" type="namedByteType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int16" type="namedInt16Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int32" type="namedInt32Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="int64" type="namedInt64Type" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="double" type="namedDoubleType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="boolean" type="namedBooleanType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="datetime" type="namedDatetimeType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="string" type="namedStringType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="object" type="namedObjectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="settingValue" type="namedSettingValueType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="namedConstructedValueTypeWithDi" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="injectedObject" type="namedInjectedObjectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="collection" type="namedCollectionTypeWithDi" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="classMember" type="namedClassMemberTypeWithDi" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="parameterValue" type="namedParameterValueType" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:element name="appDataDir">
             <xs:complexType>
                     <xs:attribute name="path" type="xs:string" use="required"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="plugins">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="plugin" minOccurs="0" maxOccurs="unbounded">
                                     <xs:complexType>
                                             <xs:attribute name="name" type="xs:string" use="required"/>
                                             <xs:attribute name="enabled" type="xs:boolean" use="optional" default="true"/>
                                     </xs:complexType>
                             </xs:element>
                     </xs:sequence>
                     <xs:attribute name="pluginsDirPath" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="additionalAssemblyProbingPaths">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="probingPath" minOccurs="0" maxOccurs="unbounded">
                                     <xs:complexType>
                                             <xs:attribute name="path" type="xs:string" use="required"/>
                                     </xs:complexType>
                             </xs:element>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="assemblies">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="assembly" minOccurs="0" maxOccurs="unbounded">
                                     <xs:complexType>
                                             <xs:attribute name="name" type="xs:string" use="required"/>
                                             <xs:attribute name="alias" type="xs:string" use="required"/>
                                             <xs:attribute name="plugin" type="xs:string" use="optional"/>
                                             <!--loadAlways is deprecated and will be deleted in the future.
                                                     All assemblies in configuration file are now added as references to dynamically generated assembly, however
                                                     .NET only loads assemblies that are used in referencing assembly-->
                                             <xs:attribute name="loadAlways" type="xs:boolean" use="optional" default="false"/>
                                             <xs:attribute name="overrideDirectory" type="xs:string" use="optional"/>
                                     </xs:complexType>
                             </xs:element>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:complexType name="typeDefinition">
             <xs:sequence minOccurs="0" maxOccurs="1">
                     <xs:element name="genericTypeParameters">
                             <xs:complexType>
                                     <xs:sequence minOccurs="1" maxOccurs="unbounded">
                                             <xs:element type="typeDefinition" name="typeDefinition"></xs:element>
                                     </xs:sequence>
                             </xs:complexType>
                     </xs:element>
             </xs:sequence>
             <xs:attribute name="type" type="xs:string" use="required"/>
             <xs:attribute name="assembly" type="xs:string" use="optional"/>
     </xs:complexType>

     <xs:complexType name="namedTypeDefinition">
             <xs:complexContent>
                     <xs:extension base="typeDefinition">
                             <xs:attribute name="alias" type="xs:string" use="required"/>
                     </xs:extension>
             </xs:complexContent>
     </xs:complexType>

     <xs:element name="typeDefinitions">
             <xs:complexType>
                     <xs:sequence minOccurs="0" maxOccurs="unbounded">
                             <xs:element name="typeDefinition" type="namedTypeDefinition"></xs:element>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <!--<xs:element name="attributeValueTransformer">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="parameters" type="defaultValuesType" minOccurs="0" maxOccurs="1" />
            </xs:sequence>
            <xs:attribute name="type" type="xs:string" use="optional" />
            <xs:attribute name="assembly" type="xs:string" use="optional" />
            <xs:attribute name="typeRef" type="xs:string" use="optional" />
        </xs:complexType>
    </xs:element>

    <xs:element name="attributeValueTransformers">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="attributeValueTransformer" minOccurs="0" maxOccurs="unbounded" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>-->

     <xs:element name="parameterSerializer">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="defaultValuesType" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="parameterSerializers">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="defaultValuesType" minOccurs="0" maxOccurs="1"/>
                             <xs:element name="serializers">
                                     <xs:complexType>
                                             <xs:sequence>
                                                     <xs:element ref="parameterSerializer" minOccurs="0" maxOccurs="unbounded"/>
                                             </xs:sequence>
                                     </xs:complexType>
                             </xs:element>
                     </xs:sequence>
                     <xs:attribute name="serializerAggregatorType" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="serializerAggregatorTypeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="diManager">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="namedValuesType" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>

                     <xs:attribute name="name" type="xs:string" use="required"/>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="diManagers">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="diManager" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="activeDiManagerName" type="xs:string" use="required"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="settings" type="settingValuesType">
     </xs:element>

     <xs:element name="controllerAssembly">
             <xs:complexType>
                     <xs:attribute name="assembly" type="xs:string" use="required"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="controllerAssemblies">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="controllerAssembly" minOccurs="0" maxOccurs="unbounded"/>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="webApi">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="controllerAssemblies" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="settingsRequestor">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="modules">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="module" minOccurs="0" maxOccurs="unbounded">
                                     <xs:complexType>
                                             <xs:sequence>
                                                     <xs:element name="parameters" type="namedValuesType" minOccurs="0" maxOccurs="1"/>
                                             </xs:sequence>
                                             <xs:attribute name="type" type="xs:string" use="optional"/>
                                             <xs:attribute name="assembly" type="xs:string" use="optional"/>
                                             <xs:attribute name="typeRef" type="xs:string" use="optional"/>
                                             <xs:attribute name="enabled" type="xs:boolean" use="optional" default="true"/>
                                     </xs:complexType>
                             </xs:element>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="implementation">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                             <xs:element name="injectedProperties" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
                     <xs:attribute name="scope" type="scopeValues" use="required"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="serviceToProxy">
             <xs:complexType>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="valueImplementation">
             <xs:complexType>
                     <xs:choice>
                             <xs:element name="collection" type="collectionTypeWithDi"/>
                             <xs:element name="settingValue" type="settingValueType"/>
                             <xs:element name="object" type="objectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="classMember" type="classMemberTypeWithDi" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="constructedValueTypeWithDi" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
                     <xs:attribute name="scope" type="scopeValues" use="required"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="service">
             <xs:complexType>
                     <xs:sequence minOccurs="1" maxOccurs="unbounded">
                             <xs:choice>
                                     <xs:element ref="implementation"/>
                                     <xs:element ref="valueImplementation"/>
                             </xs:choice>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
                     <xs:attribute name="registerIfNotRegistered" type="xs:boolean" default="false" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="proxyService">
             <xs:complexType>
                     <xs:sequence minOccurs="1" maxOccurs="1">
                             <xs:element ref="serviceToProxy"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
                     <xs:attribute name="registerIfNotRegistered" type="xs:boolean" default="false" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="selfBoundService">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                             <xs:element name="injectedProperties" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
                     <xs:attribute name="scope" type="scopeValues" use="required"/>
                     <xs:attribute name="registerIfNotRegistered" type="xs:boolean" default="false" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="services">
             <xs:complexType>
                     <xs:sequence minOccurs="0" maxOccurs="unbounded">
                             <xs:choice>
                                     <xs:element ref="service" minOccurs="1" maxOccurs="1"/>
                                     <xs:element ref="selfBoundService" minOccurs="1" maxOccurs="1"/>
                                     <xs:element ref="proxyService" minOccurs="1" maxOccurs="1"/>
                             </xs:choice>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:complexType name="autoGeneratedMemberReturnValues">
             <xs:choice minOccurs="1" maxOccurs="1">
                     <xs:element name="constructedValue" type="constructedValueTypeWithDi"/>
                     <xs:element name="injectedObject" type="injectedObjectType"/>
                     <xs:element name="byte" type="byteType"/>
                     <xs:element name="int16" type="int16Type"/>
                     <xs:element name="int32" type="int32Type"/>
                     <xs:element name="int64" type="int64Type"/>
                     <xs:element name="double" type="doubleType"/>
                     <xs:element name="boolean" type="booleanType"/>
                     <xs:element name="datetime" type="datetimeType"/>
                     <xs:element name="string" type="stringType"/>
                     <xs:element name="object" type="objectType"/>
                     <xs:element name="settingValue" type="settingValueType"/>
                     <xs:element name="collection" type="collectionTypeWithDi"/>
                     <xs:element name="classMember" type="classMemberTypeWithDi"/>
                     <xs:element name="parameterValue" type="parameterValueType"/>
             </xs:choice>
     </xs:complexType>

     <xs:element name="autoProperty">
             <xs:complexType>
                     <xs:choice minOccurs="1" maxOccurs="1">
                             <xs:element name="constructedValue" type="constructedValueTypeWithDi"/>
                             <xs:element name="injectedObject" type="injectedObjectType"/>
                             <xs:element name="byte" type="byteType"/>
                             <xs:element name="int16" type="int16Type"/>
                             <xs:element name="int32" type="int32Type"/>
                             <xs:element name="int64" type="int64Type"/>
                             <xs:element name="double" type="doubleType"/>
                             <xs:element name="boolean" type="booleanType"/>
                             <xs:element name="datetime" type="datetimeType"/>
                             <xs:element name="string" type="stringType"/>
                             <xs:element name="object" type="objectType"/>
                             <xs:element name="settingValue" type="settingValueType"/>
                             <xs:element name="collection" type="collectionTypeWithDi"/>
                             <xs:element name="classMember" type="classMemberTypeWithDi"/>
                             <xs:element name="parameterValue" type="parameterValueType"/>
                     </xs:choice>
                     <xs:attribute name="name" type="xs:string" use="required"/>
                     <xs:attribute name="returnType" use="optional" type="xs:string"/>
                     <xs:attribute name="assembly" use="optional" type="xs:string"/>
                     <xs:attribute name="returnTypeRef" use="optional" type="xs:string"/>
                     <xs:attribute name="declaringInterface" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="methodSignature">
             <xs:complexType>
                     <xs:sequence minOccurs="0" maxOccurs="unbounded">
                             <xs:choice>
                                     <xs:element name="byte">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="int16">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="int32">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="int64">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="double">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="boolean">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="datetime">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="string">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                             </xs:complexType>
                                     </xs:element>

                                     <xs:element name="object">
                                             <xs:complexType>
                                                     <xs:attribute name="paramName" use="optional"></xs:attribute>
                                                     <xs:attribute name="type" type="xs:string" use="optional"/>
                                                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                                                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
                                             </xs:complexType>
                                     </xs:element>
                             </xs:choice>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="autoMethod">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="methodSignature" minOccurs="0" maxOccurs="1"/>
                             <xs:element name="if" minOccurs="0" maxOccurs="unbounded">
                                     <xs:complexType>
                                             <xs:complexContent>
                                                     <xs:extension base="autoGeneratedMemberReturnValues">
                                                             <xs:attribute name="parameter1" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter2" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter3" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter4" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter5" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter6" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter7" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter8" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter9" type="xs:string" use="optional"/>
                                                             <xs:attribute name="parameter10" type="xs:string" use="optional"/>
                                                     </xs:extension>
                                             </xs:complexContent>
                                     </xs:complexType>
                             </xs:element>
                             <xs:element name="default" type="autoGeneratedMemberReturnValues" minOccurs="1" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
                     <xs:attribute name="returnType" use="optional" type="xs:string"/>
                     <xs:attribute name="assembly" use="optional" type="xs:string"/>
                     <xs:attribute name="returnTypeRef" use="optional" type="xs:string"/>
                     <xs:attribute name="reuseValue" type="xs:boolean" use="optional" default="false"/>
                     <xs:attribute name="declaringInterface" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="autoService">
             <xs:complexType>
                     <xs:sequence minOccurs="0" maxOccurs="unbounded">
                             <xs:choice>
                                     <xs:element ref="autoMethod" minOccurs="1" maxOccurs="1"></xs:element>
                                     <xs:element ref="autoProperty" minOccurs="1" maxOccurs="1"></xs:element>
                             </xs:choice>
                     </xs:sequence>
                     <xs:attribute name="interface" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="interfaceRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <!--<xs:complexType name="additionalAssemblyReferencesType">
    <xs:sequence minOccurs="0" maxOccurs="unbounded">
      <xs:element name="assemblyRef">
        <xs:complexType>
          <xs:attribute name="alias" type="xs:string" />
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>-->

     <xs:complexType name="autoServiceCodeGeneratorType">
             <xs:sequence minOccurs="1" maxOccurs="1">
                     <xs:choice>
                             <xs:element name="object" type="objectType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="constructedValue" type="constructedValueType" minOccurs="1" maxOccurs="1"/>
                             <xs:element name="classMember" type="classMemberType" minOccurs="1" maxOccurs="1"/>
                     </xs:choice>
             </xs:sequence>
     </xs:complexType>

     <xs:element name="autoServiceCustom">
             <xs:complexType>
                     <xs:sequence minOccurs="1" maxOccurs="1">
                             <xs:element name="autoServiceCodeGenerator" type="autoServiceCodeGeneratorType" minOccurs="1"
                                                     maxOccurs="1"/>
                             <!--<xs:element name="additionalAssemblyReferences" type="additionalAssemblyReferencesType" minOccurs="0" maxOccurs="1" />-->
                     </xs:sequence>

                     <xs:attribute name="interface" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="interfaceRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="autoGeneratedServices">
             <xs:complexType>
                     <xs:sequence minOccurs="0" maxOccurs="unbounded">
                             <xs:choice>
                                     <xs:element ref="autoService" minOccurs="1" maxOccurs="1"/>
                                     <xs:element ref="autoServiceCustom" minOccurs="1" maxOccurs="1"/>
                             </xs:choice>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="dependencyInjection">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="modules" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="services" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="autoGeneratedServices" minOccurs="1" maxOccurs="1"/>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="startupAction">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                             <xs:element name="injectedProperties" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="startupActions">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="startupAction" minOccurs="0" maxOccurs="unbounded"/>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="pluginImplementation">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element name="parameters" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                             <xs:element name="injectedProperties" type="namedValuesTypeWithDi" minOccurs="0" maxOccurs="1"/>
                     </xs:sequence>
                     <xs:attribute name="type" type="xs:string" use="optional"/>
                     <xs:attribute name="assembly" type="xs:string" use="optional"/>
                     <xs:attribute name="typeRef" type="xs:string" use="optional"/>
             </xs:complexType>
     </xs:element>

     <xs:element name="pluginSetup">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="pluginImplementation" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="typeDefinitions" minOccurs="0" maxOccurs="1"/>
                             <xs:element ref="settings" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="webApi" minOccurs="0" maxOccurs="1"/>
                             <xs:element ref="dependencyInjection" minOccurs="1" maxOccurs="1"/>
                     </xs:sequence>

                     <xs:attribute name="plugin" type="xs:string" use="required"/>
             </xs:complexType>

     </xs:element>

     <xs:element name="pluginsSetup">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="pluginSetup" minOccurs="0" maxOccurs="unbounded"/>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>

     <xs:element name="iocConfiguration">
             <xs:complexType>
                     <xs:sequence>
                             <xs:element ref="appDataDir" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="plugins" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="additionalAssemblyProbingPaths" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="assemblies" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="typeDefinitions" minOccurs="0" maxOccurs="1"/>
                             <!--<xs:element ref="attributeValueTransformers" minOccurs="0" maxOccurs="1" />-->
                             <xs:element ref="parameterSerializers" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="diManagers" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="settingsRequestor" minOccurs="0" maxOccurs="1"/>
                             <xs:element ref="settings" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="webApi" minOccurs="0" maxOccurs="1"/>
                             <xs:element ref="dependencyInjection" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="startupActions" minOccurs="1" maxOccurs="1"/>
                             <xs:element ref="pluginsSetup" minOccurs="1" maxOccurs="1"/>
                     </xs:sequence>
             </xs:complexType>
     </xs:element>
</xs:schema>

XML Configuration Template

Here is a template XML configuration file that can be used to get started. This file can be found also in folder IoC.Configuration.Content, under the folder, where Nuget package IoC.Configuration is downloaded (see the screenshot below). This file can also be downloaded from IoC.Configuration.Template.xml

_images/ioc.configuration-files.jpg

Template file:

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
<?xml version="1.0" encoding="utf-8"?>
<!--
Sample license text.
-->

<!--
   This is a simple sample configuration file to use with IoC.Configuration library.
   Some elements and attributes in this XML file should be modified per specific project.
   For more complete example, look at files IoCConfiguration_Overview.xml and some ther configuration files in test project
   IoC.Configuration.Tests at https://github.com/artakhak/IoC.Configuration/tree/master/IoC.Configuration.Tests.

   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.
-->

<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

    <!--The application should have write permissions to path specified in appDataDir. This is where dynamically generated DLLs are saved.-->
    <appDataDir path="C:\Users\user1\AppData\Local\MyApplication" />

    <plugins pluginsDirPath="c:\Program Files\MyApplication\DLLs\PluginDlls">
        <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

        <!--If Plugin1 is enabled, a folder c:\Program Files\MyApplication\DLLs\PluginDlls\Plugin1 should exist  -->
        <!--<plugin name="Plugin1" />-->
        <!--<plugin name="Plugin2" enabled="false" />-->

    </plugins>

    <additionalAssemblyProbingPaths>
        <probingPath path="c:\Program Files\MyApplication\DLLs\ThirdPartyLibs" />
    </additionalAssemblyProbingPaths>

    <assemblies>
        <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->
        <assembly name="OROptimizer.Shared" alias="oroptimizer_shared" />
        <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
        <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />
    </assemblies>

    <parameterSerializers serializerAggregatorType="OROptimizer.Serializer.TypeBasedSimpleSerializerAggregator">
        <!--
        Use parameters element to specify constructor parameters, if the type specified in 'serializerAggregatorType' attribute
        has non-default constructor.
        -->
        <!--<parameters>
        </parameters>-->
        <serializers>
        </serializers>
    </parameterSerializers>

    <!--The value of type attribute should be a type that implements IoC.Configuration.DiContainer.IDiManager-->
    <diManagers activeDiManagerName="Autofac">
        <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager">
            <!--
            Use parameters element to specify constructor parameters, if the type specified in 'type' attribute
            has non-default constructor.
            -->
            <!--<parameters>
            </parameters>-->
        </diManager>
        <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager">
        </diManager>
    </diManagers>

    <!--
    If settingsRequestor element is used, the type in type attribute should specify a type that implements
    SharedServices.ISettingsRequestor. The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency injection framework. In other words, constructor
    parameters will be injected using bindings specified in dependencyInjection element.
    -->
    <!--<settingsRequestor type="MySettingsRequestor">
    </settingsRequestor>-->

    <settings>
        <!--Example:
        <int32 name="MySetting1" value="15"/>
        -->
    </settings>

    <dependencyInjection>
        <modules>
        </modules>
        <services>
        </services>
        <autoGeneratedServices>

        </autoGeneratedServices>
    </dependencyInjection>

    <startupActions>
    </startupActions>

    <pluginsSetup>
    </pluginsSetup>
</iocConfiguration>

IoCConfiguration_Overview.xml

The file IoCConfiguration_Overview.xml provides an overview of various features of IoC.Configuration

This configuration file can be downloaded downloaded from IoCConfiguration_Overview.xml.

   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
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
<?xml version="1.0" encoding="utf-8"?>

<!--This is a demo IoC.Configuration file. Even though this configuration file, along with tests in folder SuccessfulConfigurationLoadTests
  covers many use cases, some concepts are covered in more details in separate configuration files and tests.
  Here is the list of other configuration files and tests that cover specific use cases:

  Type reuse, generic types and arrays (elements typeDefinitions and typeDefinition and referencing types defined under typeDefinitions
        element using attributes like typeRef, interfaceRef, classRef, etc): Look at configuration file
        IoCConfiguration_GenericTypesAndTypeReUse.xml and tests in folder GenericTypesAndTypeReUse.
  Element autoService: look at configuration file IoCConfiguration_autoService.xml and tests in folder AutoService.
  Element autoServiceCustom: look at configuration file IoCConfiguration_autoServiceCustom.xml and tests in folder AutoService.
  Element collection: look at configuration file IoCConfiguration_collection.xml and tests in folder Collection.
  Element classMember and _classMember: prefix in "if" elements under autoMethod elements: look at configuration file
            IoCConfiguration_classMember.xml and tests in folder ClassMember.
  Element settingValue: look at configuration file IoCConfiguration_settingValue_ReferencingInConfiguration.xml and tests in folder SettingValue.
  Element constructedValue: look at configuration file IoCConfiguration_constructedValue.xml and tests in folder ConstructedValue.
  Element proxyService: look at configuration file IoCConfiguration_proxyService.xml and tests in folder ProxyService.

  Element valueImplementation (to provide implementation as a value). Example is using a classMember, or settingValue elements to
     provide an implementation for a service.: look at configuration file IoCConfiguration_valueImplementation.xml and tests in folder ValueImplementation.
-->
<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

     <!--The application should have write permissions to path specified in appDataDir.
    This is where dynamically generated DLLs are saved.-->
     <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
     <appDataDir
             path="TestFiles\AutogeneratedDlls\IoCConfiguration_Overview" />

     <plugins pluginsDirPath="TestFiles\PluginDlls">

             <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

             <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
             <plugin name="Plugin1" />
             <plugin name="Plugin2" />
             <plugin name="Plugin3" enabled="false" />
     </plugins>

     <additionalAssemblyProbingPaths>
             <probingPath
                     path="TestFiles\ThirdPartyLibs" />
             <probingPath
                     path="TestFiles\ContainerImplementations\Autofac" />
             <probingPath
                     path="TestFiles\ContainerImplementations\Ninject" />

             <probingPath
                     path="TestFiles\DynamicallyLoadedDlls" />
             <probingPath
                     path="TestFiles\TestAssemblyResolution" />
     </additionalAssemblyProbingPaths>

     <assemblies>
             <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->
             <assembly name="OROptimizer.Shared" alias="oroptimizer_shared" />
             <assembly name="IoC.Configuration" alias="ioc_config" />
             <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
             <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

             <assembly name="TestProjects.Modules" alias="modules" />

             <!--
        Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
        an assembly in predefined folders, which also include
        probing paths specified in additionalAssemblyProbingPaths element.
        -->
             <assembly name="TestProjects.DynamicallyLoadedAssembly1"
                               alias="dynamic1" overrideDirectory="TestFiles\DynamicallyLoadedDlls"/>

             <assembly name="TestProjects.DynamicallyLoadedAssembly2"
                       alias="dynamic2" />

             <assembly name="TestProjects.TestPluginAssembly1"
                               alias="pluginassm1" plugin="Plugin1" />

             <assembly name="TestProjects.ModulesForPlugin1"
                               alias="modules_plugin1" plugin="Plugin1" />

             <assembly name="TestProjects.Plugin1WebApiControllers"
                               alias="plugin1api" plugin="Plugin1" />


             <assembly name="TestProjects.TestPluginAssembly2"
                               alias="pluginassm2" plugin="Plugin2" />

             <assembly name="TestProjects.ModulesForPlugin2"
                               alias="modules_plugin2" plugin="Plugin2"/>

             <assembly name="TestProjects.TestPluginAssembly3"
                               alias="pluginassm3" plugin="Plugin3" />

             <assembly name="TestProjects.SharedServices" alias="shared_services" />

             <assembly name="IoC.Configuration.Tests" alias="tests" />
     </assemblies>

     <typeDefinitions>
             <!--For more examples of type definitions and generic types, arrays, and re-using types defined under
             typeDefinition element look at file IoCConfiguration_GenericTypesAndTypeReUse.xml, as well as tests
             in folder GenericTypesAndTypeReUse.
             -->
             <typeDefinition alias="ReadOnlyListOf_IInterface1" type="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IInterface1]" />

             <!--The type definition below is similar to C# type System.Collections.Generic.IEnumerable<SharedServices.Interfaces.IInterface1[]>-->
             <typeDefinition alias="enumerableOfArray" type="System.Collections.Generic.IEnumerable[SharedServices.Interfaces.IInterface1#]" />

             <!--The type definition below is similar to C# type System.Collections.Generic.IList<SharedServices.Interfaces.IInterface1[]>-->
             <typeDefinition alias="listOfArray" type="System.Collections.Generic.IList" >
                     <genericTypeParameters>
                             <typeDefinition type="SharedServices.Interfaces.IInterface1#" />
                     </genericTypeParameters>
             </typeDefinition>

             <typeDefinition alias="AutoService_IInterface1" type="IoC.Configuration.Tests.AutoService.Services.IInterface1" />
             <typeDefinition alias="IActionValidator" type="SharedServices.Interfaces.IActionValidator" />
             <typeDefinition alias="IProjectGuids" type="IoC.Configuration.Tests.AutoService.Services.IProjectGuids" />
             <typeDefinition alias="ActionTypes" type="SharedServices.DataContracts.ActionTypes" />
             <typeDefinition alias="Guid" type="System.Guid" />
             <typeDefinition alias="ListOfInt" type="System.Collections.Generic.List[System.Int32]" >
             </typeDefinition>
     </typeDefinitions>

     <!--assembly attribute is not required, and only is needed to make sure the type is looked at specific assembly
    If the assembly attribute is omitted, the type will be looked in all assemblies specified in assemblies, plus some additional
    assemblies such as OROptimizer.Shared, IoC.Configuration, etc.
     -->
     <parameterSerializers serializerAggregatorType="OROptimizer.Serializer.TypeBasedSimpleSerializerAggregator"
                                               assembly="oroptimizer_shared">
             <!--
        Use parameters element to specify constructor parameters, if the type specified in 'serializerAggregatorType' attribute
        has non-default constructor.
        -->
             <!--<parameters>
        </parameters>-->
             <serializers>
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerDouble" />
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerLong" />
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerInt"/>
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerShort"/>
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerByte" />
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerBoolean" />
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerDateTime" />
                     <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerString" />
                     <parameterSerializer type="TestPluginAssembly1.Implementations.DoorSerializer" />
                     <parameterSerializer type="TestPluginAssembly2.Implementations.WheelSerializer" />

                     <parameterSerializer type="TestPluginAssembly1.Implementations.UnsignedIntSerializerWithParameters" >
                             <parameters>
                                     <int32 name="param1" value="25" />
                                     <double name="param2" value="36.5" />
                             </parameters>
                     </parameterSerializer>
             </serializers>

     </parameterSerializers>

     <!--The value of type attribute should be a type that implements
    IoC.Configuration.DiContainer.IDiManager-->
     <diManagers activeDiManagerName="Autofac">
             <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager">
                     <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute has non-default constructor.
            -->
                     <!--<parameters>
            </parameters>-->
             </diManager>

             <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager">
             </diManager>
     </diManagers>

     <!--
    If settingsRequestor element is used, the type in type attribute should
    specify a type that implements IoC.Configuration.ISettingsRequestor.
    The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency
    injection framework. In other words, constructor parameters will be injected using
    bindings specified in dependencyInjection element.
    -->
     <settingsRequestor type="SharedServices.FakeSettingsRequestor">
     </settingsRequestor>

     <settings>
             <int32 name="SynchronizerFrequencyInMilliseconds" value="5000"  />
             <double name="MaxCharge" value="155.7" />
             <string name="DisplayValue" value="Some display value" />

             <!--NOTE: For more comprehensive examples for constructedValue element,
        look at file IoCConfiguration_constructedValue.xml and tests in folder ConstructedValue.-->
             <constructedValue name="DefaultDBConnection" type="SharedServices.Implementations.SqliteDbConnection">
                     <parameters>
                             <string name="filePath" value="c:\SQLiteFiles\MySqliteDb.sqlite"/>
                     </parameters>
             </constructedValue>

             <object name="Project1Guid" typeRef="Guid" value="EA91B230-3FF8-43FA-978B-3261493D58A3" />
             <object name="Project2Guid" typeRef="Guid" value="9EDC7F1A-6BD6-4277-9015-5A9277218681" />

             <constructedValue name="Interface11_Value" type="SharedServices.Implementations.Interface11_Impl1">
                     <parameters>
                             <!-- Constructor parameter of  SharedServices.Implementations.Interface11 is injected using a constructedValue element-->
                             <constructedValue name="param1" type="SharedServices.Implementations.Interface10_Impl1" >
                                     <parameters>
                                             <int32 name="param1" value="13" />
                                     </parameters>
                                     <injectedProperties>
                                             <string name="Property2" value="Value 1"/>
                                     </injectedProperties>
                             </constructedValue>
                     </parameters>

                     <injectedProperties>
                             <!-- Property SharedServices.Implementations.Interface11.Property2 is injected using a constructedValue element-->
                             <constructedValue name="Property2" type="SharedServices.Implementations.Interface10_Impl1" >
                                     <parameters>
                                             <int32 name="param1" value="17"/>
                                     </parameters>
                                     <injectedProperties>
                                             <string name="Property2" value="Value 2"/>
                                     </injectedProperties>
                             </constructedValue>

                     </injectedProperties>
             </constructedValue>

             <!--NOTE: For more comprehensive examples for collection element,
        look at file IoCConfiguration_collection.xml and tests in folder Collection.-->
             <constructedValue name="Collections" type="IoC.Configuration.Tests.Collection.Services.DemoCollectionInjection">
                     <parameters>
                             <!--Demo of injecting a collection into a constructor of DemoCollectionInjection in constructedValue element.-->
                             <collection name="intValues" collectionType="readOnlyList" itemType="System.Int32">
                                     <int32 value="17"/>
                                     <int32 value="14"/>
                             </collection>
                     </parameters>
                     <injectedProperties>
                             <!--Demo of injecting a collection into a property of DemoCollectionInjection in constructedValue element.-->
                             <collection name="Texts" collectionType="readOnlyList" itemType="System.String">
                                     <string value="ABC, Inc"/>
                                     <string value="Microsoft"/>
                             </collection>
                     </injectedProperties>
             </constructedValue>

             <boolean name="failCustomServiceValidation" value="false"/>
     </settings>

     <!--
      webApi is an optional element that contains ASP.NET Core related
      sections such as assemblies with API controllers, etc
    -->
     <webApi>
             <controllerAssemblies>
                     <!--
                     Specify assemblies with API controllers.
                     The user of IoC.Configuration should add the assemblies to MVC using
                     IMvcBuilder.AddApplicationPart(System.Reflection.Assembly)
                     -->
                     <controllerAssembly assembly="dynamic1"></controllerAssembly>
             </controllerAssemblies>
     </webApi>

     <dependencyInjection>
             <modules>
                     <module type="IoC.Configuration.Tests.PrimitiveTypeDefaultBindingsModule" >
                             <parameters>
                                     <!--Date time can be also long value for ticks. For example the datetime value below can
                                     be replaced with 604096704000000000-->
                                     <datetime name="defaultDateTime" value="1915-04-24 00:00:00.000" />
                                     <double name="defaultDouble" value="0" />
                                     <int16 name="defaultInt16" value="0" />
                                     <classMember name="defaultInt32" class="System.Int32" memberName="MinValue"/>
                             </parameters>
                     </module>

                     <!--Type Modules.Autofac.AutofacModule1 is an Autofac module and is a
                                            subclass of Autofac.AutofacModule-->
                     <module type="Modules.Autofac.AutofacModule1" >
                             <parameters>
                                     <int32 name="param1" value="1" />
                             </parameters>
                     </module>

                     <!--Type Modules.IoC.DiModule1 is an IoC.Configuration module and is a subclass
                of IoC.Configuration.DiContainer.ModuleAbstr-->
                     <module type="Modules.IoC.DiModule1" >
                             <parameters>
                                     <int32 name="param1" value="2" />
                             </parameters>
                     </module>

                     <!--Type Modules.Ninject.NinjectModule1 is a Ninject module and is a
            subclass of Ninject.Modules.NinjectModule-->
                     <module type="Modules.Ninject.NinjectModule1" >
                             <parameters>
                                     <int32 name="param1" value="3" />
                             </parameters>
                     </module>

                     <module type="IoC.Configuration.Tests.AutoService.AutoServiceTestsModule" />
             </modules>
             <services>
                     <service type="DynamicallyLoadedAssembly1.Interfaces.IInterface1">
                             <implementation type="DynamicallyLoadedAssembly1.Implementations.Interface1_Impl1"
                                                             scope="singleton">
                             </implementation>
                     </service>

                     <service type="DynamicallyLoadedAssembly1.Interfaces.IInterface2">
                             <implementation type="DynamicallyLoadedAssembly1.Implementations.Interface2_Impl1"
                                                             scope="transient">
                             </implementation>
                     </service>

                     <service type="DynamicallyLoadedAssembly1.Interfaces.IInterface3">
                             <implementation type="DynamicallyLoadedAssembly1.Implementations.Interface3_Impl1"
                                                             scope="scopeLifetime">
                             </implementation>
                     </service>

                     <!--
            Test DI picking the default constructor when instantiating the implementation, if parameters element is
            present, and using non-default constructor otherwise, with injected parameters.
            -->
                     <service type="SharedServices.Interfaces.IInterface9">
                             <implementation type="SharedServices.Implementations.Interface9_Impl1"
                                                             scope="singleton" />
                     </service>
                     <service type="SharedServices.Interfaces.IInterface8">
                             <implementation type="SharedServices.Implementations.Interface8_Impl1"
                                                             scope="singleton">
                                     <!--
                    Since parameters is present, a default constructor will be used to construct an object, even though
                    Interface8_Impl1 has also a non default constructor.
                    -->
                                     <parameters>
                                     </parameters>
                             </implementation>

                             <implementation type="SharedServices.Implementations.Interface8_Impl2" scope="singleton">
                                     <!--
                    Since parameters is not present, DI will pick a constructor with maximum number of parameters.
                    Note, Interface8_Impl2 has two constructors, a default one, and a constructor with parameters.
                    -->
                             </implementation>
                     </service>

                     <!--Injected constructor parameters with self bound services-->
                     <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService1"
                                                       scope="singleton">
                             <parameters>
                                     <int32 name="param1" value="14" />
                                     <double name="param2" value="15.3" />
                                     <injectedObject name="param3" type="DynamicallyLoadedAssembly1.Interfaces.IInterface1" />
                             </parameters>
                     </selfBoundService>

                     <!--Injected properties with self bound services-->
                     <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService2"
                                                       scope="transient">
                             <injectedProperties>
                                     <int32 name="Property1" value="17" />
                                     <double name="Property2" value="18.1" />
                                     <injectedObject name="Property3" type="DynamicallyLoadedAssembly1.Interfaces.IInterface1" />
                             </injectedProperties>
                     </selfBoundService>

                     <!--Life time scope with self bound services-->
                     <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService3"
                                                       scope="scopeLifetime">
                     </selfBoundService>

                     <!--Test circular references between SharedServices.Interfaces.IInterface3 and SharedServices.Interfaces.IInterface4-->
                     <service type="SharedServices.Interfaces.IInterface3" >
                             <implementation type="SharedServices.Implementations.Interface3_Impl1"
                                                             scope="singleton">
                                     <injectedProperties>
                                             <injectedObject name="Property2" type="SharedServices.Interfaces.IInterface4" />
                                     </injectedProperties>
                             </implementation>
                     </service>
                     <service type="SharedServices.Interfaces.IInterface4">
                             <implementation type="SharedServices.Implementations.Interface4_Impl1"
                                                             scope="singleton">
                             </implementation>
                     </service>

                     <!--Injected constructor parameters-->
                     <service type="SharedServices.Interfaces.IInterface2" >
                             <!--Test constructor parameters-->
                             <implementation type="SharedServices.Implementations.Interface2_Impl1"
                                                             scope="singleton">
                                     <parameters>
                                             <!--The value will be de-serialized using serializer TypeBasedSimpleSerializerDateTime
                        in parameterSerializers section.-->
                                             <datetime name="param1" value="2014-10-29 23:59:59.099" />
                                             <double name="param2" value="125.1" />
                                             <injectedObject name="param3" type="SharedServices.Interfaces.IInterface3" />
                                     </parameters>
                             </implementation>

                             <!--Test injected properties-->
                             <implementation type="SharedServices.Implementations.Interface2_Impl2"
                                                             scope="singleton">
                                     <injectedProperties>
                                             <!--The value of param2 will be de-serialized using serializer TypeBasedSimpleSerializerDateTime
                        in parameterSerializers section.-->
                                             <datetime name="Property1" value="1915-04-24 00:00:00.001" />
                                             <double name="Property2" value="365.41" />
                                             <injectedObject name="Property3" type="SharedServices.Interfaces.IInterface3" />
                                     </injectedProperties>
                             </implementation>

                             <!--Test constructor parameters with injected properties. Constructor values will be overridden by
                injected properties.-->
                             <implementation type="SharedServices.Implementations.Interface2_Impl3"
                                                             scope="singleton">
                                     <parameters>
                                             <!--The value will be de-serialized using serializer TypeBasedSimpleSerializerDateTime in
                        parameterSerializers section.-->
                                             <datetime name="param1" value="2017-10-29 23:59:59.099" />
                                             <double name="param2" value="138.3" />

                                             <!--
                        Inject specific implementation. Note, there is no binding for Interface3_Impl2.
                        IoC.Configuration** will automatically register a self bound service for a type specified in elements
                        injectedObject, if the type is not an abstract type or an interface, and if it is not already
                        registered in configuration file.
                        Also, using injectedObject, we can specify a type other than a type registered for interface
                        SharedServices.Implementations.Interface3 (i.e., the type of parameter param3).
                        In other words, no matter what bindings are specified for interface SharedServices.Implementations.Interface3,
                        the object injected for parameter param3 will be of type SharedServices.Implementations.Interface3_Impl2.
                        -->
                                             <injectedObject name="param3" type="SharedServices.Implementations.Interface3_Impl2" />
                                     </parameters>
                                     <injectedProperties>
                                             <double name="Property2" value="148.3" />
                                             <!--
                        Inject specific implementation. Note, there is no binding for Interface3_Impl3.
                        IoC.Configuration** will automatically register a self bound service for a type specified in element
                        injectedObject, if the type is not an abstract type or an interface, and if it is not already
                        registered in configuration file.
                        Also, using injectedObject, we can specify a type other than a type registered for type of property
                        Property3 somewhere else. By using element injectedObject we explicitly state the type of the object
                        that should be injected, which is SharedServices.Implementations.Interface3_Impl3 in this example.
                        -->
                                             <injectedObject name="Property3" type="SharedServices.Implementations.Interface3_Impl3" />
                                     </injectedProperties>
                             </implementation>

                             <!--Test injected constructor parameters. Primitive type constructor parameters, such as DateTime and double,
                    will be injected with default values specified in module: IoC.Configuration.Tests.PrimitiveTypeDefaultBindingsModule.
                 -->
                             <implementation type="SharedServices.Implementations.Interface2_Impl4"
                                                             scope="singleton">
                             </implementation>
                     </service>

                     <!--Test constructed values to set implementation constructor parameter and property values-->
                     <service type="SharedServices.Interfaces.Airplane.IAirplane" >
                             <implementation type="SharedServices.Implementations.Airplane.Airplane" scope="singleton" >
                                     <parameters>
                                             <!--Tested constructed value in parameter-->
                                             <constructedValue name="engine" type="SharedServices.Implementations.Airplane.AirplaneEngine">
                                                     <parameters>
                                                             <!--Constructed value parameters can also be constructed values. However, for simplicity, injected parameters were used -->
                                                             <injectedObject name="blade" type="SharedServices.Interfaces.Airplane.IAirplaneEngineBlade" />
                                                             <injectedObject name="rotor" type="SharedServices.Interfaces.Airplane.IAirplaneEngineRotor" />
                                                     </parameters>
                                                     <!--constructedValue element also can have injectedProperties child element to inject values into constructed object
              properties which have public setters.-->
                                                     <!--<injectedProperties></injectedProperties>-->
                                             </constructedValue>

                                     </parameters>
                             </implementation>

                             <!--Tested constructed value to inject property values-->
                             <implementation type="SharedServices.Implementations.Airplane.Airplane" scope="singleton">

                                     <injectedProperties>
                                             <!--Injecting constructed value of type SharedServices.Implementations.Airplane.AirplaneEngine
                                             into a property SharedServices.Implementations.Airplane.Airplane.Engine-->
                                             <constructedValue name="Engine" type="SharedServices.Implementations.Airplane.AirplaneEngine">
                                                     <!--Class TestProjects.SharedServices.Implementations.Airplane.AirplaneEngine has a default constructor
                                                     which will be used in this case.-->


                                                     <!--After the object is created, the values of properties AirplaneEngine.Blade and AirplaneEngine.Rotor will
                                                     be injected using injectedProperties element.-->
                                                     <injectedProperties>

                                                             <!--Constructed value parameters can also be constructed values. However, for simplicity, injected parameters were used -->
                                                             <injectedObject name="Blade" type="SharedServices.Interfaces.Airplane.IAirplaneEngineBlade" />
                                                             <injectedObject name="Rotor" type="SharedServices.Interfaces.Airplane.IAirplaneEngineRotor" />
                                                     </injectedProperties>
                                             </constructedValue>
                                     </injectedProperties>
                             </implementation>
                     </service>

                     <service type="SharedServices.Interfaces.Airplane.IAirplaneEngineBlade">
                             <implementation  type="SharedServices.Implementations.Airplane.AirplaneEngineBlade" scope="singleton"></implementation>
                     </service>
                     <service type="SharedServices.Interfaces.Airplane.IAirplaneEngineRotor">
                             <implementation  type="SharedServices.Implementations.Airplane.AirplaneEngineRotor" scope="singleton"></implementation>
                     </service>

                     <!--<selfBoundService type="SharedServices.Implementations.ActionValidator3" scope="transient">
                             <parameters>
                                     <int32 name="intParam" value="5" />
                             </parameters>
                     </selfBoundService>-->

                     <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.CleanupJob2"
                                                       scope="transient">
                             <parameters>
                                     <injectedObject name="cleanupJobData"
                                                                     type="DynamicallyLoadedAssembly1.Implementations.CleanupJobData2" />
                             </parameters>
                     </selfBoundService>

                     <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.CleanupJob3"
                                                       scope="singleton">
                             <injectedProperties>
                                     <injectedObject name="CleanupJobData"
                                                                     type="DynamicallyLoadedAssembly1.Implementations.CleanupJobData2"/>
                             </injectedProperties>
                     </selfBoundService>

                     <service type="SharedServices.Interfaces.ICleanupJobData">
                             <implementation type="DynamicallyLoadedAssembly1.Implementations.CleanupJobData"
                                                             scope="singleton">
                             </implementation>

                     </service>

                     <!--Service implemented by plugins-->
                     <service type="SharedServices.Interfaces.IInterface5">
                             <implementation type="SharedServices.Implementations.Interface5_Impl1"
                                                             scope="singleton" />
                             <implementation type="TestPluginAssembly1.Implementations.Interface5_Plugin1Impl"
                                                             scope="singleton" />
                             <implementation type="TestPluginAssembly2.Implementations.Interface5_Plugin2Impl"
                                                             scope="transient" />
                             <implementation type="TestPluginAssembly3.Implementations.Interface5_Plugin3Impl"
                                                             scope="transient" />
                     </service>

                     <!--
                     Test registerIfNotRegistered. Note, SharedServices.Interfaces.IInterface6 is already registered in
                     module  Modules.IoC.DiModule1 for implementation SharedServices.Implementations.Interface6_Impl1.
                     Therefore, implementation SharedServices.Implementations.Interface6_Impl2 will not be registered.
                     -->
                     <service type="SharedServices.Interfaces.IInterface6"
                                      registerIfNotRegistered="true">
                             <implementation type="SharedServices.Implementations.Interface6_Impl2"
                                                             scope="singleton" />
                     </service>

                     <!--
                     Note, service SharedServices.Interfaces.IInterface7 was not registered before. Therefore its implementations
                     registered below will be registered.
                     -->
                     <service type="SharedServices.Interfaces.IInterface7"
                                      registerIfNotRegistered="true">
                             <implementation type="SharedServices.Implementations.Interface7_Impl1"
                                                             scope="singleton" />
                     </service>

                     <selfBoundService type="SharedServices.Implementations.SelfBoundService1"
                                                       registerIfNotRegistered="true" scope="singleton">

                     </selfBoundService>

                     <service type="SharedServices.Interfaces.IInterface12">
                             <implementation type="SharedServices.Implementations.Interface12_Impl1" scope="singleton">
                                     <parameters>
                                             <!--Setting with name Interface11_Value is injected into constructor parameter param1 of
                                             class SharedServices.Implementations.Interface12_Impl1-->
                                             <!--NOTE: For more comprehensive examples for settingValue element,
                                             look at file IoCConfiguration_settingValue_ReferencingInConfiguration.xml and tests in folder SettingValue.-->
                                             <settingValue name="param1" settingName="Interface11_Value"/>
                                     </parameters>
                                     <injectedProperties>
                                             <!--Setting with name Interface11_Value is injected into property
                                             SharedServices.Implementations.Interface12_Impl1.Property2-->
                                             <settingValue name="Property2" settingName="Interface11_Value"/>
                                     </injectedProperties>
                             </implementation>

                     </service>
                     <service type="SharedServices.Interfaces.IDbConnection">
                             <valueImplementation scope="singleton">
                                     <settingValue settingName="DefaultDBConnection"/>
                             </valueImplementation>
                     </service>

                     <!--NOTE: For more comprehensive examples for collection element,
                             look at file IoCConfiguration_collection.xml and tests in folder Collection.-->
                     <!--NOTE: For more comprehensive examples for valueImplementation element,
                             look at file IoCConfiguration_valueImplementation.xml and tests in folder ValueImplementation.-->
                     <service type="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IDbConnection]">
                             <valueImplementation scope="singleton">
                                     <collection>
                                             <settingValue settingName="DefaultDBConnection"/>
                                             <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
                                                     <parameters>
                                                             <string name="serverName" value="SQLSERVER2012"/>
                                                             <string name="databaseName" value="DB1"/>
                                                             <string name="userName" value="user1"/>
                                                             <string name="password" value="password123"/>
                                                     </parameters>
                                             </constructedValue>
                                             <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
                                                     <parameters>
                                                             <string name="serverName" value="SQLSERVER2016"/>
                                                             <string name="databaseName" value="DB1"/>
                                                             <string name="userName" value="user1"/>
                                                             <string name="password" value="password123"/>
                                                     </parameters>
                                             </constructedValue>
                                     </collection>
                             </valueImplementation>
                     </service>

                     <!--NOTE: For more comprehensive examples for proxyService element,
                     look at file IoCConfiguration_proxyService.xml and tests in folder ProxyService.-->
                     <!--
                     Using proxyService we can configure binding of a parent interface IActionValidatorFactoryBase in such a way, that it is resolved
                     using the same binding set up for extending interface IActionValidatorFactory.
                     For example auto-generated service IActionValidatorFactory implements methods and properties in both IActionValidatorFactory
                     as well as in parent interface IActionValidatorFactoryBase. By using proxyService we can inject the auto-generated implementation
                     for IActionValidatorFactory into classes which depend on its parent interface IActionValidatorFactoryBase.
                     -->
                     <proxyService type="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactoryBase">
                             <serviceToProxy type="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory"/>
                     </proxyService>

                     <!--START-Test binding an interface to the ame instance to which a self-bound class is bound-->
                     <selfBoundService type="SharedServices.Implementations.Interface13_Impl1" scope="singleton" />

                     <!--NOTE: Using proxyService allows us to bind
            SharedServices.Interfaces.IInterface13 to the same instance of SharedServices.Implementations.Interface13_Impl1 to which
            SharedServices.Implementations.Interface13_Impl1 was bound using selfBoundService element.

            If we used "implementation" element under service and specified a type SharedServices.Implementations.Interface13_Impl1
            instead of using "proxyService", then SharedServices.Interfaces.IInterface13 would have been
            bound to a different instance of SharedServices.Implementations.Interface13_Impl1. In other words resolving
            SharedServices.Implementations.Interface13_Impl1 and SharedServices.Interfaces.IInterface13 would have resulted in
            different instances of SharedServices.Implementations.Interface13_Impl1.
            Using "proxyService" element might be useful when we have module(s) that scan assemblies and self-binds
            non-abstract classes. In this cases we can use "proxyService" element if we want the interface
            specified in "proxyService" element to resolve to exactly the same value to which the self bound class is bound.
            -->
                     <proxyService type="SharedServices.Interfaces.IInterface13">
                             <serviceToProxy type="SharedServices.Implementations.Interface13_Impl1"/>
                     </proxyService>

                     <service type="SharedServices.Interfaces.IInterface14">
                             <implementation type="SharedServices.Implementations.Interface14_Impl1" scope="singleton" />
                     </service>

                     <!--END-Test binding an interface to the ame instance to which a self-bound class is bound-->

                     <!--Note, ActionValidatorsUser constructor has a parameter of type
                     IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactoryBase.
                     Since there is a proxyService element mapping the service IActionValidatorFactoryBase to IActionValidatorFactory,
                     an instance of auto-generated service IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory will be injected.
                     -->
                     <selfBoundService type="IoC.Configuration.Tests.ProxyService.Services.ActionValidatorsUser" scope="singleton">
                     </selfBoundService>

                     <!--System.Collections.Generic.List<System.Int32> will be bound to a list of three integers: 19, 2, 17-->
                     <service typeRef="ListOfInt">
                             <valueImplementation scope="singleton">
                                     <collection>
                                             <int32 value="19"/>
                                             <int32 value="2"/>
                                             <int32 value="17"/>
                                     </collection>
                             </valueImplementation>
                     </service>

                     <!--Resolving System.Collections.Generic.IEnumerable<System.Int32> will return the same value as resolving
            System.Collections.Generic.List<System.Int32>-->
                     <proxyService type="System.Collections.Generic.IEnumerable[System.Int32]">
                             <serviceToProxy typeRef="ListOfInt"/>
                     </proxyService>

                     <!--Resolving System.Collections.Generic.IReadOnlyList<System.Int32> will return the same value as resolving
            System.Collections.Generic.List<System.Int32>-->
                     <proxyService type="System.Collections.Generic.IReadOnlyList[System.Int32]">
                             <serviceToProxy typeRef="ListOfInt"/>
                     </proxyService>

                     <!--Resolving System.Collections.Generic.IList<System.Int32> will return the same value as resolving
            System.Collections.Generic.List<System.Int32>-->
                     <proxyService type="System.Collections.Generic.IList[System.Int32]">
                             <serviceToProxy typeRef="ListOfInt"/>
                     </proxyService>

                     <!--
                     Demo of classMember element to use static or non-static variables, properties and result of a call to parameterless
                     method to generate value used in configuration file.
                     NOTE: For more comprehensive examples for classMember element and "_classMember:" prefix in attributes in "if" elements in
                     autoService element, look at file IoCConfiguration_classMember.xml and tests in folder ClassMember.
                     -->
                     <service type="System.Collections.Generic.IReadOnlyList[IoC.Configuration.Tests.ClassMember.Services.IAppInfo]">
                             <valueImplementation scope="singleton">
                                     <collection>
                                             <constructedValue type="IoC.Configuration.Tests.ClassMember.Services.AppInfo">
                                                     <parameters>
                                                             <!--We inject the constant value IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId1
                                                             into constructor of AppInfo for parameter appId.
                                                             We can also use non constant static variables, as well as static properties and parameterless methods.
                                                             -->
                                                             <classMember name="appId"
                                                                                      class="IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds"
                                                                                      memberName="AppId1"/>
                                                     </parameters>
                                             </constructedValue>
                                             <constructedValue type="IoC.Configuration.Tests.ClassMember.Services.AppInfo">
                                                     <injectedProperties>
                                                             <!--Since SharedServices.Implementations.SelfBoundService1.IntValue is a non-static property,
                                                             an instance of SharedServices.Implementations.SelfBoundService1 will be resolved from the DI container,
                                                             and the value of IntValue of resolved instance will be injected into property AppInfo.AppId.
                                                             Note, we can also use parameterless methods.
                                                             Also, if the class in class attribute is non-interface, non-abstract, and has a public constructor,
                                                             IoC.Configuration will generated a binding for that class, if one is not specified in configuration file
                                                             or IoC.Configuration modules.
                                                             -->
                                                             <classMember name="AppId"  class="SharedServices.Implementations.SelfBoundService1"
                                                                                      memberName="IntValue"/>
                                                     </injectedProperties>
                                             </constructedValue>

                                             <constructedValue type="IoC.Configuration.Tests.ClassMember.Services.AppInfo">
                                                     <parameters>
                                                             <!--The enum value IoC.Configuration.Tests.ClassMember.Services.AppTypes.App1 is injected into constructor of
                                                             AppInfo for parameter appId-->
                                                             <classMember name="appId"
                                                                                      class="IoC.Configuration.Tests.ClassMember.Services.AppTypes"
                                                                                      memberName="App1"/>
                                                     </parameters>
                                             </constructedValue>

                                             <!--
                                             An example of calling a non static factory method to create an instance of IAppInfo.
                                             Since method IoC.Configuration.Tests.ClassMember.Services.IAppInfoFactory.CreateAppInfo(appId, appDescription)
                                             is non-static, an instance of IAppInfoFactory will be resolved using the DI container.
                                             Also, since IAppInfoFactory is an interface, a binding for IAppInfoFactory should be configured in configuration
                                             file or in some module.
                                             -->
                                             <classMember class="IoC.Configuration.Tests.ClassMember.Services.IAppInfoFactory" memberName="CreateAppInfo">
                                                     <parameters>
                                                             <int32 name="appId" value="1258"/>
                                                             <string name="appDescription" value="App info created with non-static method call."/>
                                                     </parameters>
                                             </classMember>

                                             <!--
                                             An example of calling a static factory method to create an instance of IAppInfo.
                                             -->
                                             <classMember class="IoC.Configuration.Tests.ClassMember.Services.StaticAppInfoFactory" memberName="CreateAppInfo">
                                                     <parameters>
                                                             <int32 name="appId" value="1259"/>
                                                             <string name="appDescription" value="App info created with static method call."/>
                                                     </parameters>
                                             </classMember>
                                     </collection>
                             </valueImplementation>
                     </service>

                     <service type="IoC.Configuration.Tests.ClassMember.Services.IAppInfoFactory">
                             <implementation type="IoC.Configuration.Tests.ClassMember.Services.AppInfoFactory" scope="singleton"/>
                     </service>


             </services>

             <autoGeneratedServices>
                     <!--NOTE: For more comprehensive examples for autoService element, look at
                     file IoCConfiguration_autoService.xml and tests in folder AautoService.-->

                     <!--The scope for autoService implementations is always singleton -->
                     <autoService interfaceRef="IProjectGuids" >

                             <!--Note, since property Project1 in IoC.Configuration.Tests.AutoService.Services.IProjectGuids has
                             a setter, the implementation will implement the setter as well.-->
                             <autoProperty name="Project1" returnTypeRef="Guid">
                                     <object typeRef="Guid" value="966FE6A6-76AC-4895-84B2-47E27E58FD02"/>
                             </autoProperty>

                             <autoProperty name="Project2" returnTypeRef="Guid">
                                     <object typeRef="Guid" value="AC4EE351-CE69-4F89-A362-F833489FD9A1"/>
                             </autoProperty>

                             <autoMethod name="GetDefaultProject" returnTypeRef="Guid">
                                     <!--No methodSignature is required, since the method does not have any parameters.-->
                                     <default>
                                             <!--TODO: change the returned value to classMember which references IProjectGuids.Project1 -->
                                             <object typeRef="Guid" value="1E08071B-D02C-4830-AE3C-C9E78A29EA37"/>

                                     </default>
                             </autoMethod>

                     <!---IoC.Configuration.Tests.AutoService.Services.IProjectGuids also has a method NotImplementedMethod()
                     which will be auto-implemented as well.-->
                     </autoService>

                     <!--Demo of referencing auto-implemented method parameters using parameterValue element-->
                     <autoService interface="IoC.Configuration.Tests.AutoService.Services.IAppInfoFactory">
                             <autoMethod name="CreateAppInfo" returnType="IoC.Configuration.Tests.AutoService.Services.IAppInfo">
                                     <methodSignature>
                                             <int32 paramName="appId"/>
                                             <string paramName="appDescription"/>
                                     </methodSignature>

                                     <default>
                                             <constructedValue type="IoC.Configuration.Tests.AutoService.Services.AppInfo">
                                                     <parameters>
                                                             <!--The value of name attribute is the name of constructor parameter in AppInfo-->
                                                             <!--
                                                             The value of paramName attribute is the name of parameter in IAppInfoFactory.CreateAppInfo.
                                                             This parameter should be present under autoMethod/methodSignature element.
                                                             -->
                                                             <!--In this example the values of name and paramName are similar, however they don't
                                                             have to be.-->
                                                             <parameterValue name="appId" paramName="appId" />
                                                             <parameterValue name="appDescription" paramName="appDescription" />
                                                     </parameters>
                                             </constructedValue>
                                     </default>
                             </autoMethod>
                     </autoService>

                     <!--The scope for autoService implementations is always singleton -->
                     <autoService interface="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory">

                             <autoProperty name="DefaultActionValidator" returnType="SharedServices.Interfaces.IActionValidator">
                                     <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidatorDefault"/>
                             </autoProperty>

                             <autoProperty name="PublicProjectId" returnType="System.Guid" >
                                     <object type="System.Guid" value="95E352DD-5C79-49D0-BD51-D62153570B61"/>
                             </autoProperty>

                             <autoMethod name="GetValidators"
                                                     returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]"
                                                     reuseValue="true">

                                     <methodSignature>
                                             <!--paramName attribute is optional, however it makes the auto-implementation more readable. -->
                                             <object paramName="actionType" typeRef="ActionTypes"/>
                                             <object paramName="projectGuid" type="System.Guid"/>
                                     </methodSignature>

                                     <!--Parameter actionType (parameter1) value: In this example we use class member ViewFilesList (enum value) in enumeration
                                     SharedServices.DataContracts.ActionTypes. Note, we use alias ActionTypes to reference the enum type declared in typeDefinitions section.
                                     -->
                                     <!--Parameter projectGuid (parameter2) value: The string "F79C3F23-C63F-4EB0-A513-7A8772A82B35" will be de-serialized to a System.Guid value,
                                     using the default OROptimizer.Serializer.TypeBasedSimpleSerializerGuid serializer. More serializers can be provided in section
                                     parameterSerializers-->
                                     <if parameter1="_classMember:ActionTypes.ViewFilesList" parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
                                             <collection>
                                                     <constructedValue type="SharedServices.Implementations.ActionValidator3">
                                                             <parameters>
                                                                     <int32 name="intParam" value="7"/>
                                                             </parameters>
                                                     </constructedValue>

                                                     <!--Constructor of ActionValidatorWithDependencyOnActionValidatorFactory has a parameter of type
                                                     IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory. Therefore an instance of auto-generated service  IActionValidatorFactory
                                                     will be injected.
                                                     -->
                                                     <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidatorWithDependencyOnActionValidatorFactory"/>

                                                     <constructedValue type=" IoC.Configuration.Tests.AutoService.Services.ActionValidator1" >
                                                             <parameters>
                                                                     <injectedObject name="param1" typeRef="AutoService_IInterface1" />
                                                             </parameters>
                                                             <injectedProperties>
                                                                     <!-- Note, we could have used constructedValue element to inject a constructed value into property
                                                                     ActionValidator1.Property2. However, to keep the example simple, injectedObject was used -->
                                                                     <injectedObject name="Property2" type="IoC.Configuration.Tests.AutoService.Services.IInterface2" />
                                                             </injectedProperties>
                                                     </constructedValue>

                                                     <injectedObject type="TestPluginAssembly1.Implementations.Plugin1ActionValidator"/>

                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers" memberName="ActionValidator1" />

                                                     <!--Since DefaultActionValidator property in IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider interface is
                                                     not static, IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider will be injected.
                                                     Therefore, a binding should be setup for this class (or the interface should be auto-implemented
                                                     using autoService element)
                                                     -->
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                                                                              memberName="DefaultActionValidator"/>

                                                     <!--Since Plugin3 is disabled, Plugin3ActionValidator will be ignored -->
                                                     <injectedObject type="TestPluginAssembly3.Implementations.Plugin3ActionValidator"/>
                                             </collection>
                                     </if>

                                     <!--Parameter actionType (parameter1) value: In this example we use full class path for
                                     SharedServices.DataContracts.ActionTypes in parameter1, instead of referencing a type declared in typeDefinitions element.
                                     -->
                                     <!--Parameter projectGuid (parameter2) value: In this case we reference the Project1Guid setting value in settings section, instead
                                     of using a Guid string-->
                                     <if parameter1="_classMember:ActionTypes.ViewFileContents" parameter2="_settings:Project1Guid">
                                             <collection>
                                                     <!--Since IoC.Configuration.Tests.AutoService.Services.ActionValidator1 and SharedServices.Implementations.ActionValidator2 are
                                                     concrete (non-interface and non-abstract) classes), and have public constructors,
                                                     self bound service bindings for these classes will be automatically added, if binding for these classes are not specified
                                                     in configuration file or in some module of type IoC.Configuration.DiContainer.IDiModule -->

                                                     <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator1" />

                                                     <!--Since GetViewOnlyActionvalidator() method in IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider
                                                     interface is not static, IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider will be injected.
                                                     Therefore, a binding should be setup for this class (or the interface should be auto-implemented using
                                                     autoService element).
                                                     -->
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                                                                              memberName="GetViewOnlyActionvalidator"/>
                                             </collection>
                                     </if>

                                     <!--Parameter actionType (parameter1) value: In this case we use constant value DefaultActionType declared in
                                     class IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.
                                     -->
                                     <!--Parameter projectGuid (parameter2) value: In this case we use the value of property Project1 in
                                     IoC.Configuration.Tests.AutoService.Services.IProjectGuids. Since the property Project1 is not static,
                                     class IoC.Configuration.Tests.AutoService.Services.IProjectGuids will be injected.
                                     -->
                                     <if parameter1="_classMember:IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.DefaultActionType"
                                             parameter2="_classMember:IProjectGuids.Project1">
                                             <collection>
                                                     <!--Lets assume no validators are needed for this case-->
                                             </collection>
                                     </if>

                                     <!--Parameter actionType (parameter1) value: In this case we use enum value
                                     SharedServices.DataContracts.ActionTypes.ViewFileContents. We use a shortcut (an alias) ActionTypes to reference a
                                     reference the class SharedServices.DataContracts.ActionTypes declared in typeDefintions section.
                                     -->
                                     <!--Parameter projectGuid (parameter2) value: In this case we use the value returned by a call to static method
                                     GetDefaultProjectGuid() in class IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.
                                     -->
                                     <if parameter1="_classMember:ActionTypes.ViewFileContents"
                                             parameter2="_classMember:IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.GetDefaultProjectGuid">

                                             <!--Continue here.-->
                                             <collection>
                                                     <!--Since IoC.Configuration.Tests.AutoService.Services.ActionValidator1 and SharedServices.Implementations.ActionValidator2 are
                                                     concrete (non-interface and non-abstract classes), and have public constructors,
                                                     self bound service bindings for these classes will be automatically added, if binding for these classes
                                                     are not specified in configuration file or in some module of type IoC.Configuration.DiContainer.IDiModule -->

                                                     <injectedObject type="SharedServices.Implementations.ActionValidator2" />
                                                     <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator1" />
                                             </collection>
                                     </if>

                                     <!--Note parameter2 references PublicProjectId property in this
                                     auto-generated IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory service. -->
                                     <if parameter1="_classMember:ActionTypes.ViewFilesList"
                                             parameter2="_classMember:IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory.PublicProjectId">
                                             <collection>
                                                     <!--Note, we can reference a property in this auto-generated
                                                     IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory service.-->
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory" memberName="DefaultActionValidator"/>
                                             </collection>

                                     </if>

                                     <!--if none of conditions above are true, the default value will be returned by interface implementation.-->
                                     <default>
                                             <collection>
                                                     <!--We can also call a method or property in auto-generated interface, or in one of its base interfaces.-->
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory" memberName="DefaultActionValidator"/>
                                                     <injectedObject type="SharedServices.Implementations.ActionValidator3" />
                                                     <injectedObject type="DynamicallyLoadedAssembly2.ActionValidator4"/>
                                             </collection>
                                     </default>
                             </autoMethod>

                             <!--Overloaded method GetValidators uses parameters of types System.Int2 and System.string, instead of
                             SharedServices.DataContracts.ActionTypes and System.Guid, as in case above.-->
                             <autoMethod name="GetValidators"
                                                     returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]">
                                     <methodSignature>
                                             <!--paramName attribute is optional, however it makes the auto-implementation more readable. -->
                                             <int32 paramName="actionTypeId"/>
                                             <string paramName="projectGuid" />
                                     </methodSignature>

                                     <!-- Attributes parameter1 and parameter2 map values of parameters param1 and param2 in GetInstances() method to returned values. -->
                                     <if parameter1="0" parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
                                             <collection>
                                                     <injectedObject type="SharedServices.Implementations.ActionValidator3" />
                                                     <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator4" />
                                             </collection>
                                     </if>

                                     <default>
                                             <collection>
                                                     <!--We can also call a method or property in auto-generated interface, or in one of its base interfaces.-->
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory"
                                                                              memberName="DefaultActionValidator"/>
                                                     <injectedObject type="SharedServices.Implementations.ActionValidator3" />
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers"
                                                                              memberName="GetDefaultActionValidator" />
                                                     <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                                                                              memberName="AdminLevelActionValidator"/>
                                             </collection>
                                     </default>
                             </autoMethod>

                     <!--Note, interface IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory also has a method
                     void SomeMethodThatWillNotBeImplemented(int param1, string param2) and a property int SomeUnImplementedProperty { get; },'
                     we chose not to implement in configuration file. Unimplemented methods and properties will be auto-implemented to return default values,
                     based on return type defaults.
                     -->
                     </autoService>

                     <!--IMemberAmbiguityDemo demonstrates cases when there are multiple occurrences
                     of auto-generated methods and properties with same signatures and return types
                     in IMemberAmbiguityDemo and its base interfaces.
                     -->
                     <autoService interface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo">
                             <!--GetIntValues(): IReadOnlyList<int> GetIntValues(int param1, string param2)-->
                             <autoMethod name="GetIntValues" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]" >
                                     <methodSignature>
                                             <int32 paramName="param1"/>
                                             <string paramName="param2"/>
                                     </methodSignature>
                                     <if parameter1="1" parameter2="str1">
                                             <collection>
                                                     <int32 value="17"/>
                                             </collection>
                                     </if>
                                     <default>
                                             <collection>
                                                     <int32 value="18"/>
                                                     <int32 value="19"/>
                                             </collection>
                                     </default>
                             </autoMethod>

                             <!--
                             This method is declared in IMemberAmbiguityDemo_Parent3, which is a base interface for IMemberAmbiguityDemo.
                             We can provide implementation for this interface, even though it has a similar signature and return type as the method
                             method IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo.GetIntValues.
                             By using the attribute 'declaringInterface', we make a distinction between these two.
                             -->
                             <autoMethod name="GetIntValues" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]"
                                                     declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent3">
                                     <methodSignature>
                                             <int32 paramName="param1"/>
                                             <string paramName="param2"/>
                                     </methodSignature>
                                     <default>
                                             <collection>
                                                     <int32 value="3"/>
                                             </collection>
                                     </default>
                             </autoMethod>

                             <!---
                             The method GetDbConnection(System.Guid appGuid) that return IDbConnection is in two base interfaces
                             of IMemberAmbiguityDemo: in IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1 and in
                             IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2.
                             Therefore, to avoid ambiguity, we have to specify the declaring interface in attribute 'declaringInterface'.
                             We can specify an implementation for IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2.GetDbConnection(),
                             and IoC.Configuration will generate a similar auto-implementation for the similar method in IMemberAmbiguityDemo_Parent1
                             as well.
                             -->
                             <autoMethod name="GetDbConnection" returnType="SharedServices.Interfaces.IDbConnection"
                                                     declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2">
                                     <methodSignature>
                                             <object paramName="appGuid" type="System.Guid"/>
                                     </methodSignature>
                                     <default>
                                             <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
                                                     <parameters>
                                                             <string name="filePath" value="c:\mySqliteDatabase.sqlite"/>
                                                     </parameters>
                                             </constructedValue>
                                     </default>
                             </autoMethod>

                             <!--
                             Both IMemberAmbiguityDemo_Parent1 and IMemberAmbiguityDemo_Parent2 have properties called DefaultDbConnection
                             with the same return types. We can auto-implement this property for each of these interfaces by using
                             declaringInterface attribute in autoProperty element to explicitly specify the interface that own
                             the property (declaringInterface can be used in autoMethod as well as demonstrated above)
                             -->
                             <!--Auto-implementation of IMemberAmbiguityDemo_Parent1.DefaultDbConnection-->
                             <autoProperty name="DefaultDbConnection" returnType="SharedServices.Interfaces.IDbConnection"
                                                       declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1">
                                     <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
                                             <parameters>
                                                     <string name="filePath" value="c:\IMemberAmbiguityDemo_Parent1_Db.sqlite"/>
                                             </parameters>
                                     </constructedValue>
                             </autoProperty>

                             <!--Auto-implementation of IMemberAmbiguityDemo_Parent2.DefaultDbConnection-->
                             <autoProperty name="DefaultDbConnection" returnType="SharedServices.Interfaces.IDbConnection"
                                                       declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2">
                                     <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
                                             <parameters>
                                                     <string name="filePath" value="c:\IMemberAmbiguityDemo_Parent2_Db.sqlite"/>
                                             </parameters>
                                     </constructedValue>
                             </autoProperty>

                             <!--
                             Method GetNumericValue() occurs in both IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2
                             and IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1_Parent. However, since the return types
                             are different (System.Double in IMemberAmbiguityDemo_Parent2, and System.Int32 in IMemberAmbiguityDemo_Parent1_Parent),
                             we can auto-implement both them, without using attribute 'declaringInterface' to separate these two implementation.
                             -->
                             <!--IMemberAmbiguityDemo_Parent2.GetNumericValue() with return type of System.Double-->
                             <autoMethod name="GetNumericValue" returnType="System.Double" >
                                     <default>
                                             <double value="17.3"/>
                                     </default>
                             </autoMethod>

                             <!--IMemberAmbiguityDemo_Parent1_Parent.GetNumericValue() with return type of System.Int32-->
                             <autoMethod name="GetNumericValue" returnType="System.Int32" >
                                     <default>
                                             <int32 value="19"/>
                                     </default>
                             </autoMethod>

                             <!--
                             Property NumericValue occurs in both IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1
                             and IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2. However, since the return types
                             are different (System.Double in IMemberAmbiguityDemo_Parent1, and System.Int32 in IMemberAmbiguityDemo_Parent2),
                             we can auto-implement both them, without using attribute 'declaringInterface' to separate these two implementation.
                             -->
                             <!--IMemberAmbiguityDemo_Parent1.NumericValue with return type of System.Double-->
                             <autoProperty name="NumericValue" returnType="System.Double" >
                                     <double value="18.2"/>
                             </autoProperty>

                             <!--IMemberAmbiguityDemo_Parent2.NumericValue with return type of System.Int32-->
                             <autoProperty name="NumericValue" returnType="System.Int32" >
                                     <int32 value="14"/>
                             </autoProperty>

                             <!---Auto-implementing Method with optional parameters:
                             int MethodWithOptionalParameters(int param1, double param2 = 3.5, int param3=7); -->
                             <autoMethod name="MethodWithOptionalParameters" returnType="System.Int32">
                                     <methodSignature>
                                             <int32 paramName="param1"/>
                                             <double paramName="param2"/>
                                             <int32 paramName="param3"/>
                                     </methodSignature>
                                     <if parameter1="3" parameter2="3.5" parameter3="7">
                                             <int32 value="17"/>
                                     </if>
                                     <default>
                                             <int32 value="18"/>
                                     </default>
                             </autoMethod>
                     </autoService>

                     <!--Interface specified in autoServiceCustom is auto-implemented by implementation of
                     IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator
                     that is specified in autoServiceCodeGenerator element.-->
                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.DataRepositories.IAuthorsRepository">
                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator">
                                             <parameters>
                                                     <int32 name="someDemoConstructorParameter" value="15" />
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>

                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.DataRepositories.IBooksRepository">
                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator">
                                             <parameters>
                                                     <int32 name="someDemoConstructorParameter" value="25" />
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>

                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.DataRepositories.IAuthorBooksRepository">
                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator">
                                             <parameters>
                                                     <int32 name="someDemoConstructorParameter" value="35" />
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>
             </autoGeneratedServices>
     </dependencyInjection>

     <startupActions>
             <startupAction type="DynamicallyLoadedAssembly1.Implementations.StartupAction1">
                     <!--Use parameters element to specify constructor parameters if necessary.-->
                     <!--<parameters></parameters>-->
                     <!--Use injectedProperties element to inject properties into startup action if necessary.-->
                     <!--<injectedProperties></injectedProperties>-->
             </startupAction>
             <startupAction type="DynamicallyLoadedAssembly1.Implementations.StartupAction2">
             </startupAction>
     </startupActions>

     <pluginsSetup>
             <pluginSetup plugin="Plugin1">
                     <!--The type in pluginImplementation should be non-abstract class
                that implements IoC.Configuration.IPlugin and which has a public constructor-->
                     <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1">
                             <parameters>
                                     <int64 name="param1" value="25" />
                             </parameters>
                             <injectedProperties>
                                     <int64 name="Property2" value="35"/>
                             </injectedProperties>
                     </pluginImplementation>
                     <settings>
                             <int32 name="Int32Setting1" value="25" />
                             <int64 name="Int64Setting1" value="38" />
                             <string name="StringSetting1" value="String Value 1" />
                     </settings>

                     <webApi>
                             <controllerAssemblies>
                                     <!--
                      Specify assemblies with API controllers.
                      The user of IoC.Configuration should add the assemblies to MVC using
                      IMvcBuilder.AddApplicationPart(System.Reflection.Assembly)
                    -->
                                     <controllerAssembly assembly="pluginassm1" />
                                     <controllerAssembly assembly="plugin1api" />
                             </controllerAssemblies>
                     </webApi>
                     <dependencyInjection>
                             <modules>
                                     <module type="ModulesForPlugin1.Ninject.NinjectModule1">
                                             <parameters>
                                                     <int32 name="param1" value="101" />
                                             </parameters>
                                     </module>

                                     <module type="ModulesForPlugin1.Autofac.AutofacModule1" >
                                             <parameters>
                                                     <int32 name="param1" value="102" />
                                             </parameters>
                                     </module>

                                     <module type="ModulesForPlugin1.IoC.DiModule1" >
                                             <parameters>
                                                     <int32 name="param1" value="103" />
                                             </parameters>
                                     </module>
                             </modules>
                             <services>
                                     <service type="TestPluginAssembly1.Interfaces.IDoor">
                                             <implementation type="TestPluginAssembly1.Implementations.Door"
                                                                             scope="transient">
                                                     <parameters>
                                                             <int32 name="Color" value="3" />
                                                             <double name="Height" value="180" />
                                                     </parameters>
                                             </implementation>
                                     </service>
                                     <service type="TestPluginAssembly1.Interfaces.IRoom">
                                             <implementation type="TestPluginAssembly1.Implementations.Room"
                                                                             scope="transient">
                                                     <parameters>
                                                             <object name="door1" type="TestPluginAssembly1.Interfaces.IDoor"
                                                                             value="5,185.1" />
                                                             <injectedObject name="door2" type="TestPluginAssembly1.Interfaces.IDoor" />
                                                     </parameters>
                                                     <injectedProperties>
                                                             <object name="Door2" type="TestPluginAssembly1.Interfaces.IDoor"
                                                                             value="7,187.3" />
                                                     </injectedProperties>
                                             </implementation>
                                     </service>
                             </services>
                             <autoGeneratedServices>
                                     <!--The scope for autoService implementations is always singleton -->
                                     <autoService interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
                                             <autoMethod name="GetValidators"
                                                                     returnType="System.Collections.Generic.IEnumerable[TestPluginAssembly1.Interfaces.IResourceAccessValidator]"
                                                                     reuseValue="true" >
                                                     <methodSignature>
                                                             <string paramName="resourceName"/>
                                                     </methodSignature>
                                                     <if parameter1="public_pages">
                                                             <collection>
                                                                     <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                                                             </collection>

                                                     </if>
                                                     <if parameter1="admin_pages">
                                                             <collection>
                                                                     <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                                                                     <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                                                             </collection>
                                                     </if>
                                                     <default>
                                                             <collection>
                                                                     <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                                                                     <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                                                             </collection>
                                                     </default>
                                             </autoMethod>
                                     </autoService>
                             </autoGeneratedServices>
                     </dependencyInjection>
             </pluginSetup>

             <pluginSetup plugin="Plugin2">
                     <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2">
                             <parameters>
                                     <boolean name="param1" value="true" />
                                     <double name="param2" value="25.3" />
                                     <string name="param3" value="String value" />
                             </parameters>
                             <injectedProperties>
                                     <double name="Property2" value="5.3" />
                             </injectedProperties>
                     </pluginImplementation>
                     <settings>
                     </settings>

                     <dependencyInjection>
                             <modules>
                             </modules>
                             <services>
                                     <service type="TestPluginAssembly2.Interfaces.IWheel">
                                             <implementation type="TestPluginAssembly2.Implementations.Wheel"
                                                                             scope="transient">
                                                     <parameters>
                                                             <int32 name="Color" value="5" />
                                                             <double name="Height" value="48" />
                                                     </parameters>
                                             </implementation>
                                     </service>
                                     <service type="TestPluginAssembly2.Interfaces.ICar">
                                             <implementation type="TestPluginAssembly2.Implementations.Car"
                                                                             scope="transient">
                                                     <parameters>
                                                             <object name="wheel1" type="TestPluginAssembly2.Interfaces.IWheel" value="248,40" />
                                                     </parameters>
                                                     <injectedProperties>
                                                             <object name="Wheel1" type="TestPluginAssembly2.Interfaces.IWheel" value="27,45" />
                                                             <injectedObject name="Wheel2" type="TestPluginAssembly2.Interfaces.IWheel"/>
                                                     </injectedProperties>
                                             </implementation>
                                     </service>
                             </services>
                             <autoGeneratedServices>

                             </autoGeneratedServices>
                     </dependencyInjection>
             </pluginSetup>

             <pluginSetup plugin="Plugin3">
                     <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3">
                     </pluginImplementation>
                     <settings></settings>
                     <webApi>
                             <controllerAssemblies>
                                     <!--
                                     Specify assemblies with API controllers.
                                     The user of IoC.Configuration should add the assemblies to MVC using
                                     IMvcBuilder.AddApplicationPart(System.Reflection.Assembly)
                                     -->
                                     <controllerAssembly assembly="pluginassm3" />
                             </controllerAssemblies>
                     </webApi>
                     <dependencyInjection>
                             <modules>
                             </modules>
                             <services>
                             </services>
                             <autoGeneratedServices>
                             </autoGeneratedServices>
                     </dependencyInjection>
             </pluginSetup>
     </pluginsSetup>
</iocConfiguration>

IoCConfiguration_GenericTypesAndTypeReUse.xml

This configuration file can be downloaded downloaded from IoCConfiguration_GenericTypesAndTypeReUse.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
<?xml version="1.0" encoding="utf-8"?>

<!--This configuration demonstrates usage of types. Types can be specified in various elements either by using 'type' attribute, and an
   optional 'assembly' attribute, or by using typeRef (or some other variations, such as interfaceRef), to reference a type defined in section
   'typeDefinitions'.
   In other words, every typeRef attribute can be replaced with 'type' (along with optional 'assembly' attribute)-->
<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

  <!--The application should have write permissions to path specified in appDataDir.
    This is where dynamically generated DLLs are saved.-->
  <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
  <appDataDir
      path="TestFiles\AutogeneratedDlls\DynamicFiles_TypeTests" />

  <plugins pluginsDirPath="TestFiles\PluginDlls">

    <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

    <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
    <plugin name="Plugin1" />
    <plugin name="Plugin2" />
  </plugins>

  <additionalAssemblyProbingPaths>
    <probingPath
        path="TestFiles\ThirdPartyLibs" />
    <probingPath
        path="TestFiles\ContainerImplementations\Autofac" />
    <probingPath
        path="TestFiles\ContainerImplementations\Ninject" />
    <probingPath
        path="TestFiles\DynamicallyLoadedDlls" />
  </additionalAssemblyProbingPaths>

  <assemblies>
    <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

    <!--
    Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
    an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
    -->
    <assembly name="OROptimizer.Shared" alias="oroptimizer_shared" />
    <assembly name="IoC.Configuration" alias="ioc_config" />
    <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
    <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

    <assembly name="TestProjects.Modules" alias="modules" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly1"
              alias="dynamic1" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly2"
              alias="dynamic2" />

    <assembly name="TestProjects.TestPluginAssembly1"
              alias="pluginassm1" plugin="Plugin1" />

    <assembly name="TestProjects.TestPluginAssembly2"
              alias="pluginassm2" plugin="Plugin2" />

    <assembly name="TestProjects.ModulesForPlugin1"
              alias="modules_plugin1" plugin="Plugin1" />

    <assembly name="TestProjects.SharedServices" alias="shared_services" />

    <assembly name="IoC.Configuration.Tests" alias="tests" />

    <assembly name="System.Private.CoreLib" alias="corlib"/>
  </assemblies>

  <typeDefinitions>
    <typeDefinition alias="ReadOnlyListOf_IInterface1" type="System.Collections.Generic.IReadOnlyList">
      <genericTypeParameters>
        <typeDefinition type="SharedServices.Interfaces.IInterface1" assembly="shared_services" />
      </genericTypeParameters>
    </typeDefinition>

    <typeDefinition alias="IEnumerableOf_IInterface1"
                    type="System.Collections.Generic.IEnumerable[SharedServices.Interfaces.IInterface1]" />

    <typeDefinition alias="IGeneric1_1_of_Interface1_Impl1"
                    type="SharedServices.Interfaces.Generic.IGeneric1_1[SharedServices.Implementations.Interface1_Impl1]">
    </typeDefinition>

    <!--The type definition below is similar to C# type SharedServices.Interfaces.IInterface1[]-->
    <typeDefinition alias="arrayOfInterface1" type="SharedServices.Interfaces.IInterface1#" />

    <!--The type definition below is similar to C# type System.Collections.Generic.IEnumerable<SharedServices.Interfaces.IInterface1[]>-->
    <typeDefinition alias="enumerableOfArray" type="System.Collections.Generic.IEnumerable[SharedServices.Interfaces.IInterface1#]" />

    <!--The type definition below is similar to C# type System.Collections.Generic.IList<SharedServices.Interfaces.IInterface1[]>-->
    <typeDefinition alias="listOfArray" type="System.Collections.Generic.IList" >
      <genericTypeParameters>
        <typeDefinition type="SharedServices.Interfaces.IInterface1#" />
      </genericTypeParameters>
    </typeDefinition>

    <!--The type definition below is similar to C# type
    SharedServices.Interfaces.Generic.IGeneric4_2<SharedServices.Interfaces.IInterface1[], SharedServices.Interfaces.IInterface2[]>[]-->
    <typeDefinition alias="arraysOfGenericTypes" type="SharedServices.Interfaces.Generic.IGeneric4_2[SharedServices.Interfaces.IInterface1#, SharedServices.Interfaces.IInterface2#]#" />

    <typeDefinition alias="Generic1_1_of_Interface1_Impl1" type="SharedServices.Implementations.Generic.Generic1_1[SharedServices.Implementations.Interface1_Impl1]">
    </typeDefinition>

    <typeDefinition alias="Generic4_2_a" type="SharedServices.Implementations.Generic.Generic4_2" >
      <genericTypeParameters>
        <typeDefinition type="System.Int32" />
        <typeDefinition type="System.String" />
      </genericTypeParameters>
    </typeDefinition>

    <typeDefinition alias="Generic4_2_b" type="SharedServices.Implementations.Generic.Generic4_2" >
      <genericTypeParameters>
        <typeDefinition type="SharedServices.Implementations.Generic.Generic2_1[SharedServices.Implementations.Interface1_Impl1]" />
        <typeDefinition type="SharedServices.Implementations.Generic.Generic2_1">
          <genericTypeParameters>
            <typeDefinition type="System.Int64" />
          </genericTypeParameters>
        </typeDefinition>
      </genericTypeParameters>
    </typeDefinition>

    <typeDefinition alias="Generic4_2_c" type="SharedServices.Implementations.Generic.Generic4_2" >
      <genericTypeParameters>
        <typeDefinition type="SharedServices.Interfaces.Generic.IGeneric2_1">
          <genericTypeParameters>
            <typeDefinition type="System.String" />
          </genericTypeParameters>
        </typeDefinition>
        <typeDefinition type="SharedServices.Interfaces.Generic.IGeneric2_1[SharedServices.Implementations.Interface1_Impl2]" />
      </genericTypeParameters>
    </typeDefinition>

    <typeDefinition alias="Generic4_2_d" type="SharedServices.Implementations.Generic.Generic4_2" >
      <genericTypeParameters>
        <typeDefinition type="SharedServices.Interfaces.Generic.IGeneric2_1">
          <genericTypeParameters>
            <typeDefinition type="System.String" />
          </genericTypeParameters>
        </typeDefinition>

        <typeDefinition type="SharedServices.Interfaces.Generic.IGeneric2_1">
          <genericTypeParameters>
            <typeDefinition type="System.Double" />
          </genericTypeParameters>
        </typeDefinition>
      </genericTypeParameters>
    </typeDefinition>

    <typeDefinition alias="Interface1" type="SharedServices.Interfaces.IInterface1"></typeDefinition>
    <typeDefinition alias="Interface1_Impl1" type="SharedServices.Implementations.Interface1_Impl1"></typeDefinition>
    <typeDefinition alias="module2" type="Modules.IoC.DiModule2" />
    <typeDefinition alias="SerializerAggregator" type="OROptimizer.Serializer.TypeBasedSimpleSerializerAggregator" />
    <typeDefinition alias="TestTypeRefTestClass3Serializer" type="IoC.Configuration.Tests.GenericTypesAndTypeReUse.GenericTypesAndTypeReUseTests.TestTypeRefTestClass3Serializer" />
    <typeDefinition alias="TestTypeRefTestClass1" type="IoC.Configuration.Tests.GenericTypesAndTypeReUse.GenericTypesAndTypeReUseTests.TestTypeRefTestClass1" />
    <typeDefinition alias="TestTypeRefTestClass2" type="IoC.Configuration.Tests.GenericTypesAndTypeReUse.GenericTypesAndTypeReUseTests.TestTypeRefTestClass2" />
    <typeDefinition alias="TestTypeRefTestClass3" type="IoC.Configuration.Tests.GenericTypesAndTypeReUse.GenericTypesAndTypeReUseTests.TestTypeRefTestClass3" />
    <!--Plugin types can be used in non plugin definitions. However, usage of this types in other non-plugin sections should confirm'
    to certain restictions.-->
    <typeDefinition alias="pluginTypeDef" type="TestPluginAssembly1.Implementations.Window" assembly="pluginassm1"></typeDefinition>

  </typeDefinitions>

  <parameterSerializers serializerAggregatorTypeRef="SerializerAggregator">
    <!--
        Use parameters element to specify constructor parameters, if the type specified in 'serializerAggregatorType' attribute
        has non-default constructor.
        -->
    <!--<parameters>
        </parameters>-->
    <serializers>
      <parameterSerializer typeRef="TestTypeRefTestClass3Serializer" />
    </serializers>
  </parameterSerializers>

  <!--The value of type attribute should be a type that implements
    IoC.Configuration.DiContainer.IDiManager-->
  <diManagers activeDiManagerName="Autofac">
    <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
               assembly="ninject_ext">
      <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute has non-default constructor.
            -->
      <!--<parameters>
            </parameters>-->
    </diManager>

    <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
               assembly="autofac_ext">
    </diManager>
  </diManagers>

  <!--
    If settingsRequestor element is used, the type in type attribute should
    specify a type that implements IoC.Configuration.ISettingsRequestor.
    The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency
    injection framework. In other words, constructor parameters will be injected using
    bindings specified in dependencyInjection element.
    -->
  <settingsRequestor type="IoC.Configuration.Tests.GenericTypesAndTypeReUse.SettingsRequestor"
                     assembly="tests">
    <!-- TODO:-->
  </settingsRequestor>

  <settings>

    <constructedValue name="GenericSetting1" typeRef="Generic1_1_of_Interface1_Impl1" >
      <parameters>
        <constructedValue name="param1" typeRef="Interface1_Impl1">
        </constructedValue>
      </parameters>
    </constructedValue>
  </settings>

  <dependencyInjection>
    <modules>
      <module typeRef="module2">
        <parameters>
          <constructedValue name="param1" typeRef="Interface1_Impl1" />
        </parameters>
      </module>
    </modules>
    <services>

      <selfBoundService typeRef="Interface1_Impl1" scope="singleton" />
      <service typeRef="Interface1">
        <implementation typeRef="Interface1_Impl1" scope="singleton"></implementation>
      </service>

      <service typeRef="IGeneric1_1_of_Interface1_Impl1">
        <valueImplementation scope="singleton">
          <settingValue settingName="GenericSetting1"/>
        </valueImplementation>
        <implementation typeRef="Generic1_1_of_Interface1_Impl1" scope="singleton"></implementation>
        <implementation type="SharedServices.Implementations.Generic.Generic1_1[SharedServices.Implementations.Interface1_Impl1]" scope="singleton" />
      </service>

      <service type="SharedServices.Interfaces.Generic.IGeneric2_1[SharedServices.Implementations.Generic.Generic3_1[System.Int32]]" >
        <implementation type="SharedServices.Implementations.Generic.Generic2_1[SharedServices.Implementations.Generic.Generic3_1[System.Int32]]"
                        scope="singleton">
          <parameters>
            <constructedValue name="param1" type="SharedServices.Implementations.Generic.Generic3_1[System.Int32]">
              <parameters>
                <int32 name="param1" value="17"/>
              </parameters>
            </constructedValue>
          </parameters>
        </implementation>
      </service>

      <selfBoundService typeRef="Generic4_2_b" scope="singleton">
        <parameters>
          <constructedValue name="param1" type="SharedServices.Implementations.Generic.Generic2_1[SharedServices.Implementations.Interface1_Impl1]">
            <parameters>
              <injectedObject name="param1" type="SharedServices.Implementations.Interface1_Impl1" />
            </parameters>
          </constructedValue>
        </parameters>
        <injectedProperties>
          <constructedValue name="Value2" type="SharedServices.Implementations.Generic.Generic2_1[System.Int64]">
            <parameters>
              <int64 name="param1" value="19"/>
            </parameters>
          </constructedValue>
        </injectedProperties>
      </selfBoundService>

      <selfBoundService typeRef="TestTypeRefTestClass2" scope="singleton">
      </selfBoundService>

      <selfBoundService typeRef="TestTypeRefTestClass1" scope="singleton">
        <parameters>
          <injectedObject name="param1" typeRef="TestTypeRefTestClass2" />
          <object name="param2" typeRef="TestTypeRefTestClass3" value="5"/>
        </parameters>
        <injectedProperties>
          <injectedObject name="Property3" typeRef="TestTypeRefTestClass2" />
          <object name="Property4" typeRef="TestTypeRefTestClass3" value="7"/>
        </injectedProperties>
      </selfBoundService>
    </services>
    <autoGeneratedServices>

    </autoGeneratedServices>
  </dependencyInjection>

  <startupActions>
    <startupAction type="IoC.Configuration.Tests.GenericTypesAndTypeReUse.StartupAction1"
                   assembly="tests">
      <!-- TODO:-->
      <!--Use parameters element to specify constructor parameters if necessary.-->
      <!--<parameters></parameters>-->
      <!--Use injectedProperties element to inject properties into startup action if necessary.-->
      <!--<injectedProperties></injectedProperties>-->
    </startupAction>

  </startupActions>

  <pluginsSetup>
    <pluginSetup plugin="Plugin1">
      <!--The type in pluginImplementation should be non-abstract class
                that implements IoC.Configuration.IPlugin and which has a public constructor-->
      <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
      </pluginImplementation>

      <typeDefinitions>
        <!--Generic1_1_of_Interface1_Impl1 type definition overrides the definition in non-plugins section.-->
        <typeDefinition alias="Generic1_1_of_Interface1_Impl1" type="SharedServices.Implementations.Generic.Generic1_1[TestPluginAssembly1.Implementations.Interface1_Impl1]">
        </typeDefinition>

        <typeDefinition alias="ReadOnlyListOfGenericType" type="System.Collections.Generic.IReadOnlyList" assembly="corlib">
          <genericTypeParameters>
            <typeDefinition type="SharedServices.Implementations.Generic.Generic3_1" >
              <genericTypeParameters>
                <typeDefinition type="SharedServices.Implementations.Interface1_Impl1" />
              </genericTypeParameters>
            </typeDefinition>
          </genericTypeParameters>
        </typeDefinition>

        <typeDefinition alias="IDoor" type="TestPluginAssembly1.Interfaces.IDoor"></typeDefinition>
        <typeDefinition alias="Door" type="TestPluginAssembly1.Implementations.Door"></typeDefinition>
        <typeDefinition alias="plugin1Module" type="ModulesForPlugin1.IoC.DiModule2"></typeDefinition>

      </typeDefinitions>

      <settings>
        <constructedValue name="PluginGenericSetting1" typeRef="Generic1_1_of_Interface1_Impl1" >
          <parameters>
            <constructedValue name="param1" type="TestPluginAssembly1.Implementations.Interface1_Impl1">
            </constructedValue>
          </parameters>
        </constructedValue>
      </settings>

      <dependencyInjection>
        <modules>
          <module typeRef="plugin1Module">
            <parameters>
              <constructedValue name="param1" typeRef="Door">
                <parameters>
                  <int32 name="color" value="255"/>
                  <int32 name="height" value="200"/>
                </parameters>
              </constructedValue>
            </parameters>
          </module>
        </modules>
        <services>
          <selfBoundService typeRef="Door" scope="singleton">
            <parameters>
              <int32 name="color" value="258"/>
              <int32 name="height" value="100" />
            </parameters>
          </selfBoundService>
          <service typeRef="IDoor">
            <implementation typeRef="Door" scope="singleton">
              <parameters>
                <int32 name="color" value="255"/>
                <int32 name="height" value="25"/>
              </parameters>
            </implementation>
          </service>
        </services>
        <autoGeneratedServices>

        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>

    <pluginSetup plugin="Plugin2">
      <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2_TypeTests" assembly="pluginassm2">
        <!--<parameters>

        </parameters>-->
      </pluginImplementation>
      <settings>
      </settings>
      <dependencyInjection>
        <modules>
        </modules>
        <services>

        </services>
        <autoGeneratedServices>
        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>
  </pluginsSetup>
</iocConfiguration>

IoCConfiguration_autoService.xml

This configuration file can be downloaded downloaded from IoCConfiguration_autoService.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
 <?xml version="1.0" encoding="utf-8"?>

 <!--
    The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
    which can be found in folder IoC.Configuration.Content in output directory.
    The schema file can also be downloaded from
    http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
    project in Github.com.

    To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
    field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

    Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
    folders specified in this configuration file.
    Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
 -->

 <iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

   <!--The application should have write permissions to path specified in appDataDir.
     This is where dynamically generated DLLs are saved.-->
   <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
   <appDataDir
     path="TestFiles\AutogeneratedDlls\DynamicFiles_AutoServiceTests" />

   <plugins pluginsDirPath="TestFiles\PluginDlls">

     <!--
         Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
         The plugin folders will be included in assembly resolution mechanism.
         -->

     <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
     <plugin name="Plugin1" />
     <plugin name="Plugin2" enabled="true" />
     <plugin name="Plugin3" enabled="false" />
   </plugins>

   <additionalAssemblyProbingPaths>
     <probingPath
       path="TestFiles\ThirdPartyLibs" />
     <probingPath
       path="TestFiles\ContainerImplementations\Autofac" />
     <probingPath
       path="TestFiles\ContainerImplementations\Ninject" />
     <probingPath
       path="TestFiles\DynamicallyLoadedDlls" />
   </additionalAssemblyProbingPaths>

   <assemblies>
     <!--Assemblies should be in one of the following locations:
         1) Executable's folder
         2) In folder specified in additionalAssemblyProbingPaths element.
         3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

     <!--
         Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
         an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
     -->
     <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
     <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

     <assembly name="TestProjects.Modules" alias="modules" />

     <assembly name="TestProjects.DynamicallyLoadedAssembly1"
               alias="dynamic1" />

     <assembly name="TestProjects.DynamicallyLoadedAssembly2"
               alias="dynamic2" />

     <assembly name="TestProjects.TestPluginAssembly1"
               alias="pluginassm1" plugin="Plugin1" />

     <assembly name="TestProjects.TestPluginAssembly2"
               alias="pluginassm2" plugin="Plugin2" />

     <assembly name="TestProjects.TestPluginAssembly3"
               alias="pluginassm3" plugin="Plugin3" />

     <assembly name="TestProjects.ModulesForPlugin1"
               alias="modules_plugin1" plugin="Plugin1" />

     <assembly name="TestProjects.SharedServices" alias="shared_services" />

     <assembly name="IoC.Configuration.Tests" alias="tests" />
   </assemblies>

   <typeDefinitions>
     <typeDefinition alias="AutoService_IInterface1" type="IoC.Configuration.Tests.AutoService.Services.IInterface1" />
     <typeDefinition alias="IActionValidator" type="SharedServices.Interfaces.IActionValidator" />
     <typeDefinition alias="IProjectGuids" type="IoC.Configuration.Tests.AutoService.Services.IProjectGuids" />
     <typeDefinition alias="ActionTypes" type="SharedServices.DataContracts.ActionTypes" />
     <typeDefinition alias="Guid" type="System.Guid" />
   </typeDefinitions>

   <parameterSerializers>
     <serializers></serializers>
   </parameterSerializers>

   <!--The value of type attribute should be a type that implements
     IoC.Configuration.DiContainer.IDiManager-->
   <diManagers activeDiManagerName="Autofac">
     <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
                assembly="ninject_ext">
       <!--
             Use parameters element to specify constructor parameters,
             if the type specified in 'type' attribute has non-default constructor.
             -->
       <!--<parameters>
             </parameters>-->
     </diManager>

     <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
                assembly="autofac_ext">
     </diManager>
   </diManagers>

   <!--
     If settingsRequestor element is used, the type in type attribute should
     specify a type that implements IoC.Configuration.ISettingsRequestor.
     The implementation specifies a collection of required settings that should be present
     in settings element.
     Note, the type specified in type attribute is fully integrated into a dependency
     injection framework. In other words, constructor parameters will be injected using
     bindings specified in dependencyInjection element.
     -->

   <settings>
     <constructedValue name="DefaultDBConnection" type="SharedServices.Implementations.SqliteDbConnection">
       <parameters>
         <string name="filePath" value="c:\SQLiteFiles\MySqliteDb.sqlite"/>
       </parameters>
     </constructedValue>

     <object name="Project1Guid" typeRef="Guid" value="EA91B230-3FF8-43FA-978B-3261493D58A3" />
     <object name="Project2Guid" typeRef="Guid" value="9EDC7F1A-6BD6-4277-9015-5A9277218681" />
   </settings>

   <dependencyInjection>
     <modules>
       <module type="IoC.Configuration.Tests.PrimitiveTypeDefaultBindingsModule">
         <parameters>
           <!--Date time can be also long value for ticks. For example the datetime value below can
           be replaced with 604096704000000000-->
           <datetime name="defaultDateTime" value="1915-04-24 00:00:00.000" />
           <double name="defaultDouble" value="0" />
           <int16 name="defaultInt16" value="0" />
           <classMember name="defaultInt32" class="System.Int32" memberName="MinValue"/>
         </parameters>
       </module>

       <module type="IoC.Configuration.Tests.AutoService.AutoServiceTestsModule" />
     </modules>
     <services>

     </services>

     <autoGeneratedServices>

       <!--The scope for autoService implementations is always singleton -->
       <autoService interfaceRef="IProjectGuids" >

         <!--Note, since property Project1 in IoC.Configuration.Tests.AutoService.Services.IProjectGuids has
         a setter, the implementation will implement the setter as well.-->
         <autoProperty name="Project1" returnTypeRef="Guid">
           <object typeRef="Guid" value="966FE6A6-76AC-4895-84B2-47E27E58FD02"/>
         </autoProperty>

         <autoProperty name="Project2" returnTypeRef="Guid">
           <object typeRef="Guid" value="AC4EE351-CE69-4F89-A362-F833489FD9A1"/>
         </autoProperty>

         <autoMethod name="GetDefaultProject" returnTypeRef="Guid">
           <!--No methodSignature is required, since the method does not have any parameters.-->
           <default>
             <!--TODO: change the returned value to classMember which references IProjectGuids.Project1 -->
             <object typeRef="Guid" value="1E08071B-D02C-4830-AE3C-C9E78A29EA37"/>

           </default>
         </autoMethod>

         <!---IoC.Configuration.Tests.AutoService.Services.IProjectGuids also has a method NotImplementedMethod()
         which will be auto-implemented as well.-->
       </autoService>

       <!--Demo of referencing auto-implemented method parameters using parameterValue element-->
       <autoService interface="IoC.Configuration.Tests.AutoService.Services.IAppInfoFactory">
         <autoMethod name="CreateAppInfo" returnType="IoC.Configuration.Tests.AutoService.Services.IAppInfo">
           <methodSignature>
             <int32 paramName="appId"/>
             <string paramName="appDescription"/>
           </methodSignature>

           <default>
             <constructedValue type="IoC.Configuration.Tests.AutoService.Services.AppInfo">
               <parameters>
                 <!--The value of name attribute is the name of constructor parameter in AppInfo-->
                 <!--
                 The value of paramName attribute is the name of parameter in IAppInfoFactory.CreateAppInfo.
                 This parameter should be present under autoMethod/methodSignature element.
                 -->
                 <!--In this example the values of name and paramName are similar, however they don't
                 have to be.-->
                 <parameterValue name="appId" paramName="appId" />
                 <parameterValue name="appDescription" paramName="appDescription" />
               </parameters>
             </constructedValue>
           </default>
         </autoMethod>
       </autoService>

       <!--The scope for autoService implementations is always singleton -->
       <autoService interface="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory">

         <autoProperty name="DefaultActionValidator" returnType="SharedServices.Interfaces.IActionValidator">
           <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidatorDefault"/>
         </autoProperty>

         <autoProperty name="PublicProjectId" returnType="System.Guid" >
             <object type="System.Guid" value="95E352DD-5C79-49D0-BD51-D62153570B61"/>
         </autoProperty>

         <autoMethod name="GetValidators"
                     returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]"
                     reuseValue="true">

           <methodSignature>
             <!--paramName attribute is optional, however it makes the auto-implementation more readable. -->

             <object paramName="actionType" typeRef="ActionTypes"/>
             <object paramName="projectGuid" type="System.Guid"/>
           </methodSignature>

           <!--Parameter actionType (parameter1) value: In this example we use class member ViewFilesList (enum value) in enumeration
           SharedServices.DataContracts.ActionTypes. Note, we use alias ActionTypes to reference the enum type declared in typeDefinitions section.
           -->
           <!--Parameter projectGuid (parameter2) value: The string "F79C3F23-C63F-4EB0-A513-7A8772A82B35" will be de-serialized to a System.Guid value,
           using the default OROptimizer.Serializer.TypeBasedSimpleSerializerGuid serializer. More serializers can be provided in section
           parameterSerializers-->
           <if parameter1="_classMember:ActionTypes.ViewFilesList" parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
             <collection>
               <constructedValue type="SharedServices.Implementations.ActionValidator3">
                 <parameters>
                   <int32 name="intParam" value="7"/>
                 </parameters>
               </constructedValue>

               <!--Constructor of ActionValidatorWithDependencyOnActionValidatorFactory has a parameter of type
               IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory. Therefore an instance of auto-generated service  IActionValidatorFactory
               will be injected.
               -->
               <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidatorWithDependencyOnActionValidatorFactory"/>

               <constructedValue type=" IoC.Configuration.Tests.AutoService.Services.ActionValidator1" >
                 <parameters>
                   <injectedObject name="param1" typeRef="AutoService_IInterface1" />
                 </parameters>
                 <injectedProperties>
                   <!-- Note, we could have used constructedValue element to inject a constructed value into property
                     ActionValidator1.Property2. However, to keep the example simple, injectedObject was used -->
                   <injectedObject name="Property2" type="IoC.Configuration.Tests.AutoService.Services.IInterface2" />
                 </injectedProperties>
               </constructedValue>

               <injectedObject type="TestPluginAssembly1.Implementations.Plugin1ActionValidator"/>

               <classMember class="IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers" memberName="ActionValidator1" />

               <!--Since DefaultActionValidator property in IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider interface is
               not static, IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider will be injected.
               Therefore, a binding should be setup for this class (or the interface should be auto-implemented
               using autoService element)
               -->
               <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                            memberName="DefaultActionValidator"/>

               <!--Since Plugin3 is disabled, Plugin3ActionValidator will be ignored -->
               <injectedObject type="TestPluginAssembly3.Implementations.Plugin3ActionValidator"/>
             </collection>
           </if>

           <!--Parameter actionType (parameter1) value: In this example we use full class path for
           SharedServices.DataContracts.ActionTypes in parameter1, instead of referencing a type declared in typeDefinitions element.
           -->
           <!--Parameter projectGuid (parameter2) value: In this case we reference the Project1Guid setting value in settings section, instead
           of using a Guid string-->
           <if parameter1="_classMember:ActionTypes.ViewFileContents" parameter2="_settings:Project1Guid">
             <collection>
               <!--Since IoC.Configuration.Tests.AutoService.Services.ActionValidator1 and SharedServices.Implementations.ActionValidator2 are
                 concrete (non-interface and non-abstract) classes), and have public constructors,
                 self bound service bindings for these classes will be automatically added, if binding for these classes are not specified
                 in configuration file or in some module of type IoC.Configuration.DiContainer.IDiModule -->

               <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator1" />

               <!--Since GetViewOnlyActionvalidator() method in IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider
               interface is not static, IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider will be injected.
               Therefore, a binding should be setup for this class (or the interface should be auto-implemented using
               autoService element).
               -->
               <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                            memberName="GetViewOnlyActionvalidator"/>
             </collection>
           </if>

           <!--Parameter actionType (parameter1) value: In this case we use constant value DefaultActionType declared in
           class IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.
           -->
           <!--Parameter projectGuid (parameter2) value: In this case we use the value of property Project1 in
           IoC.Configuration.Tests.AutoService.Services.IProjectGuids. Since the property Project1 is not static,
           class IoC.Configuration.Tests.AutoService.Services.IProjectGuids will be injected.
           -->
           <if parameter1="_classMember:IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.DefaultActionType"
               parameter2="_classMember:IProjectGuids.Project1">
             <collection>
               <!--Lets assume no validators are needed for this case-->
             </collection>
           </if>

           <!--Parameter actionType (parameter1) value: In this case we use enum value
           SharedServices.DataContracts.ActionTypes.ViewFileContents. We use a shortcut (an alias) ActionTypes to reference a
           reference the class SharedServices.DataContracts.ActionTypes declared in typeDefintions section.
           -->
           <!--Parameter projectGuid (parameter2) value: In this case we use the value returned by a call to static method
           GetDefaultProjectGuid() in class IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.
           -->
           <if parameter1="_classMember:ActionTypes.ViewFileContents"
               parameter2="_classMember:IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers.GetDefaultProjectGuid">

             <!--Continue here.-->
             <collection>
               <!--Since IoC.Configuration.Tests.AutoService.Services.ActionValidator1 and SharedServices.Implementations.ActionValidator2 are
                 concrete (non-interface and non-abstract classes), and have public constructors,
                 self bound service bindings for these classes will be automatically added, if binding for these classes
                 are not specified in configuration file or in some module of type IoC.Configuration.DiContainer.IDiModule -->

               <injectedObject type="SharedServices.Implementations.ActionValidator2" />
               <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator1" />
             </collection>
           </if>

           <!--Note parameter2 references PublicProjectId property in this
           auto-generated IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory service. -->
           <if parameter1="_classMember:ActionTypes.ViewFilesList"
               parameter2="_classMember:IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory.PublicProjectId">
             <collection>
               <!--Note, we can reference a property in this auto-generated
               IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory service.-->
               <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory" memberName="DefaultActionValidator"/>
             </collection>

           </if>
           <!--if none of conditions above are true, the default value will be returned by interface implementation.-->

           <default>
             <collection>
               <!--We can also call a method or property in auto-generated interface, or in one of its base interfaces.-->
               <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory" memberName="DefaultActionValidator"/>
               <injectedObject type="SharedServices.Implementations.ActionValidator3" />
               <injectedObject type="DynamicallyLoadedAssembly2.ActionValidator4"/>
             </collection>
           </default>
         </autoMethod>

         <!--Overloaded method GetValidators uses parameters of types System.Int32 and System.string, instead of
         SharedServices.DataContracts.ActionTypes and System.Guid, as in case above.-->
         <autoMethod name="GetValidators"
                     returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]">
           <methodSignature>
             <!--paramName attribute is optional, however it makes the auto-implementation more readable. -->
             <int32 paramName="actionTypeId"/>
             <string paramName="projectGuid" />
           </methodSignature>

           <!-- Attributes parameter1 and parameter2 map values of parameters param1 and param2 in GetInstances() method to returned values. -->
           <if parameter1="0" parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
             <collection>
               <injectedObject type="SharedServices.Implementations.ActionValidator3" />
               <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator4" />
             </collection>
           </if>

           <default>
             <collection>
               <!--We can also call a method or property in auto-generated interface, or in one of its base interfaces.-->
               <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory"
                            memberName="DefaultActionValidator"/>
               <injectedObject type="SharedServices.Implementations.ActionValidator3" />
               <classMember class="IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers"
                            memberName="GetDefaultActionValidator" />
               <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                            memberName="AdminLevelActionValidator"/>
             </collection>
           </default>
         </autoMethod>

         <!--Note, interface IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory also has a method
         void SomeMethodThatWillNotBeImplemented(int param1, string param2) and a property int SomeUnImplementedProperty { get; },'
         we chose not to implement in configuration file. Unimplemented methods and properties will be auto-implemented to return default values,
         based on return type defaults.
         -->
       </autoService>

       <!--IMemberAmbiguityDemo demonstrates cases when there are multiple occurrences
       of auto-generated methods and properties with same signatures and return types
       in IMemberAmbiguityDemo and its base interfaces.
       -->
       <autoService interface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo">
         <!--GetIntValues(): IReadOnlyList<int> GetIntValues(int param1, string param2)-->
         <autoMethod name="GetIntValues" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]" >
           <methodSignature>
             <int32 paramName="param1"/>
             <string paramName="param2"/>
           </methodSignature>
           <if parameter1="1" parameter2="str1">
             <collection>
               <int32 value="17"/>
             </collection>
           </if>
           <default>
             <collection>
               <int32 value="18"/>
               <int32 value="19"/>
             </collection>
           </default>
         </autoMethod>

         <!--
         This method is declared in IMemberAmbiguityDemo_Parent3, which is a base interface for IMemberAmbiguityDemo.
         We can provide implementation for this interface, even though it has a similar signature and return type as the method
         IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo.GetIntValues.
         By using the attribute 'declaringInterface', we make a distinction between these two.
         -->
         <autoMethod name="GetIntValues" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]"
                     declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent3">
           <methodSignature>
             <int32 paramName="param1"/>
             <string paramName="param2"/>
           </methodSignature>
           <default>
             <collection>
               <int32 value="3"/>
             </collection>
           </default>
         </autoMethod>

         <!---
         The method GetDbConnection(System.Guid appGuid) that return IDbConnection is in two base interfaces
         of IMemberAmbiguityDemo: in IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1 and in
         IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2.
         Therefore, to avoid ambiguity, we have to specify the declaring interface in attribute 'declaringInterface'.
         We can specify an implementation for IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2.GetDbConnection(),
         and IoC.Configuration will generate a similar auto-implementation for the similar method in IMemberAmbiguityDemo_Parent1
         as well.
         -->
         <autoMethod name="GetDbConnection" returnType="SharedServices.Interfaces.IDbConnection"
                     declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2">
           <methodSignature>
             <object paramName="appGuid" type="System.Guid"/>
           </methodSignature>
           <default>
             <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
               <parameters>
                 <string name="filePath" value="c:\mySqliteDatabase.sqlite"/>
               </parameters>
             </constructedValue>
           </default>
         </autoMethod>

         <!--
         Both IMemberAmbiguityDemo_Parent1 and IMemberAmbiguityDemo_Parent2 have properties called DefaultDbConnection
         with the same return types. We can auto-implement this property for each of these interfaces by using
         declaringInterface attribute in autoProperty element to explicitly specify the interface that own
         the property (declaringInterface can be used in autoMethod as well as demonstrated above)
         -->
         <!--Auto-implementation of IMemberAmbiguityDemo_Parent1.DefaultDbConnection-->
         <autoProperty name="DefaultDbConnection" returnType="SharedServices.Interfaces.IDbConnection"
                       declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1">
           <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
             <parameters>
               <string name="filePath" value="c:\IMemberAmbiguityDemo_Parent1_Db.sqlite"/>
             </parameters>
           </constructedValue>
         </autoProperty>

         <!--Auto-implementation of IMemberAmbiguityDemo_Parent2.DefaultDbConnection-->
         <autoProperty name="DefaultDbConnection" returnType="SharedServices.Interfaces.IDbConnection"
                       declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2">
           <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
             <parameters>
               <string name="filePath" value="c:\IMemberAmbiguityDemo_Parent2_Db.sqlite"/>
             </parameters>
           </constructedValue>
         </autoProperty>

         <!--
         Method GetNumericValue() occurs in both IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2
         and IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1_Parent. However, since the return types
         are different (System.Double in IMemberAmbiguityDemo_Parent2, and System.Int32 in IMemberAmbiguityDemo_Parent1_Parent),
         we can auto-implement both them, without using attribute 'declaringInterface' to separate these two implementation.
         -->
         <!--IMemberAmbiguityDemo_Parent2.GetNumericValue() with return type of System.Double-->
         <autoMethod name="GetNumericValue" returnType="System.Double" >
           <default>
             <double value="17.3"/>
           </default>
         </autoMethod>

         <!--IMemberAmbiguityDemo_Parent1_Parent.GetNumericValue() with return type of System.Int32-->
         <autoMethod name="GetNumericValue" returnType="System.Int32" >
           <default>
             <int32 value="19"/>
           </default>
         </autoMethod>

         <!--
         Property NumericValue occurs in both IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1
         and IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2. However, since the return types
         are different (System.Double in IMemberAmbiguityDemo_Parent1, and System.Int32 in IMemberAmbiguityDemo_Parent2),
         we can auto-implement both them, without using attribute 'declaringInterface' to separate these two implementation.
         -->
         <!--IMemberAmbiguityDemo_Parent1.NumericValue with return type of System.Double-->
         <autoProperty name="NumericValue" returnType="System.Double" >
           <double value="18.2"/>
         </autoProperty>

         <!--IMemberAmbiguityDemo_Parent2.NumericValue with return type of System.Int32-->
         <autoProperty name="NumericValue" returnType="System.Int32" >
           <int32 value="14"/>
         </autoProperty>

         <!---Auto-implementing Method with optional parameters:
           int MethodWithOptionalParameters(int param1, double param2 = 3.5, int param3=7); -->
         <autoMethod name="MethodWithOptionalParameters" returnType="System.Int32">
           <methodSignature>
             <int32 paramName="param1"/>
             <double paramName="param2"/>
             <int32 paramName="param3"/>
           </methodSignature>
           <if parameter1="3" parameter2="3.5" parameter3="7">
             <int32 value="17"/>
           </if>
           <default>
             <int32 value="18"/>
           </default>
         </autoMethod>
       </autoService>

       <autoService interface="IoC.Configuration.Tests.AutoService.Services.INullableTypesTestInterface">
         <autoMethod name="GetNullableInt" returnType="System.Nullable[System.Int32]">
           <default>
             <int32 value="17"/>
           </default>
         </autoMethod>

         <autoMethod name="GetNullablesList" returnType="System.Collections.Generic.IReadOnlyList[System.Nullable[System.Int32]]">
           <default>
             <collection>
               <int32 value="12" />
               <int32 value="18" />
             </collection>
           </default>
         </autoMethod>

         <autoMethod name="MethodWithNullableParameter" returnType="System.Int32">
           <methodSignature>
             <object paramName="value"  type="System.Nullable[System.Double]"/>
           </methodSignature>

           <default>
             <int32 value="23"/>
           </default>
         </autoMethod>

         <autoMethod name="MethodWithParameterAsListOfNullableValues" returnType="System.Int32">
           <methodSignature>
             <object paramName="value"  type="System.Collections.Generic.IReadOnlyList[System.Nullable[System.Double]]"/>
           </methodSignature>

           <default>
             <int32 value="19"/>
           </default>
         </autoMethod>

       </autoService>
     </autoGeneratedServices>
   </dependencyInjection>

   <startupActions>

   </startupActions>

   <pluginsSetup>
     <pluginSetup plugin="Plugin1">
       <!--The type in pluginImplementation should be non-abstract class
                 that implements IoC.Configuration.IPlugin and which has a public constructor-->
       <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
       </pluginImplementation>

       <settings>
         <int32 name="Int32Setting1" value="10"/>
         <string name="StringSetting1" value="Some text"/>
       </settings>

       <dependencyInjection>
         <modules>

         </modules>
         <services>

         </services>

         <autoGeneratedServices>
           <autoService interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
             <autoMethod name="GetValidators"
                         returnType="System.Collections.Generic.IEnumerable[TestPluginAssembly1.Interfaces.IResourceAccessValidator]"
                         reuseValue="true" >
               <methodSignature>
                 <string paramName="resourceName"/>
               </methodSignature>
               <if parameter1="public_pages">
                 <collection>
                   <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                 </collection>

               </if>
               <if parameter1="admin_pages">
                 <collection>
                   <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                   <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                 </collection>
               </if>
               <default>
                 <collection>
                   <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                   <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                 </collection>
               </default>
             </autoMethod>
           </autoService>
         </autoGeneratedServices>
       </dependencyInjection>
     </pluginSetup>

     <pluginSetup plugin="Plugin2">
       <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2" assembly="pluginassm2">
         <parameters>
           <boolean name="param1" value="true" />
           <double name="param2" value="25.3" />
           <string name="param3" value="String value" />
         </parameters>
       </pluginImplementation>
       <settings>
       </settings>
       <dependencyInjection>
         <modules>
         </modules>
         <services>
         </services>
         <autoGeneratedServices>
         </autoGeneratedServices>
       </dependencyInjection>
     </pluginSetup>

     <pluginSetup plugin="Plugin3">
       <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3" assembly="pluginassm3">

       </pluginImplementation>
       <settings>
       </settings>
       <dependencyInjection>
         <modules>
         </modules>
         <services>
         </services>
         <autoGeneratedServices>
         </autoGeneratedServices>
       </dependencyInjection>
     </pluginSetup>

   </pluginsSetup>
 </iocConfiguration>

IoCConfiguration_autoServiceCustom.xml

This configuration file can be downloaded downloaded from IoCConfiguration_autoServiceCustom.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
 <?xml version="1.0" encoding="utf-8"?>

 <!--
    The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
    which can be found in folder IoC.Configuration.Content in output directory.
    The schema file can also be downloaded from
    http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
    project in Github.com.

    To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
    field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

    Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
    folders specified in this configuration file.
    Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
 -->

 <iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

     <!--The application should have write permissions to path specified in appDataDir.
     This is where dynamically generated DLLs are saved.-->
     <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
     <appDataDir
             path="TestFiles\AutogeneratedDlls\DynamicFiles_AutoServiceCustomTests"  />

     <plugins pluginsDirPath="TestFiles\PluginDlls">

             <!--
         Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
         The plugin folders will be included in assembly resolution mechanism.
         -->

             <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
     </plugins>

     <additionalAssemblyProbingPaths>
             <probingPath
               path="TestFiles\ThirdPartyLibs" />
             <probingPath
               path="TestFiles\ContainerImplementations\Autofac" />
             <probingPath
               path="TestFiles\ContainerImplementations\Ninject" />
             <probingPath
               path="TestFiles\DynamicallyLoadedDlls" />
     </additionalAssemblyProbingPaths>

     <assemblies>
             <!--Assemblies should be in one of the following locations:
         1) Executable's folder
         2) In folder specified in additionalAssemblyProbingPaths element.
         3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

             <!--
         Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
         an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
         -->
             <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
             <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

             <assembly name="TestProjects.SharedServices" alias="shared_services" />
             <assembly name="IoC.Configuration.Tests" alias="tests" />

             <assembly name="TestProjects.DynamicallyLoadedAssembly1" alias="dynamic1" />
     </assemblies>

     <typeDefinitions>

     </typeDefinitions>

     <parameterSerializers>
             <serializers></serializers>
     </parameterSerializers>

     <!--The value of type attribute should be a type that implements
     IoC.Configuration.DiContainer.IDiManager-->
     <diManagers activeDiManagerName="Autofac">
             <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
                                assembly="ninject_ext">
                     <!--
             Use parameters element to specify constructor parameters,
             if the type specified in 'type' attribute has non-default constructor.
             -->
                     <!--<parameters>
             </parameters>-->
             </diManager>

             <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
                                assembly="autofac_ext">
             </diManager>
     </diManagers>

     <!--
     If settingsRequestor element is used, the type in type attribute should
     specify a type that implements IoC.Configuration.ISettingsRequestor.
     The implementation specifies a collection of required settings that should be present
     in settings element.
     Note, the type specified in type attribute is fully integrated into a dependency
     injection framework. In other words, constructor parameters will be injected using
     bindings specified in dependencyInjection element.
     -->

     <settings>
             <boolean name="failCustomServiceValidation" value="false"/>
     </settings>

     <dependencyInjection>
             <modules>

             </modules>
             <services>
                     <service type="SharedServices.Interfaces.IDbConnection" >
                             <valueImplementation scope="singleton">
                                     <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
                                             <parameters>
                                                     <string name="serverName" value="MainServer"/>
                                                     <string name="databaseName" value="DB1"/>
                                                     <string name="userName" value="sa"/>
                                                     <string name="password" value="password1"/>
                                             </parameters>
                                     </constructedValue>
                             </valueImplementation>
                     </service>

             </services>
             <autoGeneratedServices>

                     <!--Interface specified in autoServiceCustom is auto-implemented by implementation of
                     IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator
                     that is specified in autoServiceCodeGenerator element.-->
                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.DataRepositories.IAuthorsRepository">

                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator">
                                             <parameters>
                                                     <int32 name="someDemoConstructorParameter" value="15" />
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>

                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.DataRepositories.IBooksRepository">
                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator">
                                             <parameters>
                                                     <int32 name="someDemoConstructorParameter" value="25" />
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>

                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.DataRepositories.IAuthorBooksRepository">
                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator">
                                             <parameters>
                                                     <int32 name="someDemoConstructorParameter" value="35" />
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>

                     <!--Custom auto service to test failures-->
                     <autoServiceCustom interface="IoC.Configuration.Tests.AutoServiceCustom.ClassesForFailureTests.DogAbstr">
                             <autoServiceCodeGenerator>
                                     <constructedValue type="IoC.Configuration.Tests.AutoServiceCustom.ClassesForFailureTests.CustomAutoServiceCodeGeneratorForFailureTests" >
                                             <parameters>
                                                     <boolean name="simulateValidateFails" value="false"/>
                                                     <boolean name="simulateValidateOnIoCContainerLoadedFails" value="false"/>
                                                     <boolean name="simulateGenerateCSharpFailure" value="false"/>
                                                     <boolean name="simulateAssemblyBuildFailure" value="false"/>
                                             </parameters>
                                     </constructedValue>
                             </autoServiceCodeGenerator>
                     </autoServiceCustom>
             </autoGeneratedServices>

     </dependencyInjection>

     <startupActions>

     </startupActions>

     <pluginsSetup>
     </pluginsSetup>
 </iocConfiguration>

IoCConfiguration_proxyService.xml

This configuration file can be downloaded downloaded from IoCConfiguration_proxyService.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
<?xml version="1.0" encoding="utf-8"?>

<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

    <!--The application should have write permissions to path specified in appDataDir.
      This is where dynamically generated DLLs are saved.-->
    <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
    <appDataDir
            path="TestFiles\AutogeneratedDlls\DynamicFiles_ProxyServiceTests"/>

    <plugins
            pluginsDirPath="TestFiles\PluginDlls">

        <!--
            Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
            The plugin folders will be included in assembly resolution mechanism.
            -->

        <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
        <plugin name="Plugin1"/>
        <plugin name="Plugin2" enabled="true"/>
        <plugin name="Plugin3" enabled="false"/>
    </plugins>

    <additionalAssemblyProbingPaths>
        <probingPath
                path="TestFiles\ThirdPartyLibs"/>
        <probingPath
                path="TestFiles\ContainerImplementations\Autofac"/>
        <probingPath
                path="TestFiles\ContainerImplementations\Ninject"/>
        <probingPath
                path="TestFiles\DynamicallyLoadedDlls"/>
    </additionalAssemblyProbingPaths>

    <assemblies>
        <!--Assemblies should be in one of the following locations:
            1) Executable's folder
            2) In folder specified in additionalAssemblyProbingPaths element.
            3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

        <!--
        Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
        an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
        -->
        <assembly name="IoC.Configuration.Autofac" alias="autofac_ext"/>
        <assembly name="IoC.Configuration.Ninject" alias="ninject_ext"/>

        <assembly name="TestProjects.Modules" alias="modules"/>

        <assembly name="TestProjects.DynamicallyLoadedAssembly1"
                  alias="dynamic1"/>

        <assembly name="TestProjects.DynamicallyLoadedAssembly2"
                  alias="dynamic2"/>

        <assembly name="TestProjects.TestPluginAssembly1"
                  alias="pluginassm1" plugin="Plugin1"/>

        <assembly name="TestProjects.TestPluginAssembly2"
                  alias="pluginassm2" plugin="Plugin2"/>

        <assembly name="TestProjects.TestPluginAssembly3"
                  alias="pluginassm3" plugin="Plugin3"/>

        <assembly name="TestProjects.ModulesForPlugin1"
                  alias="modules_plugin1" plugin="Plugin1"/>

        <assembly name="TestProjects.SharedServices" alias="shared_services"/>

        <assembly name="IoC.Configuration.Tests" alias="tests"/>
    </assemblies>

    <typeDefinitions>
        <typeDefinition alias="IAppData" type="IoC.Configuration.Tests.ProxyService.Services.IAppData"/>
        <typeDefinition alias="AppData" type="IoC.Configuration.Tests.ProxyService.Services.AppData"/>
        <typeDefinition alias="Guid" type="System.Guid"/>
        <typeDefinition alias="ListOfInt" type="System.Collections.Generic.List[System.Int32]"/>
    </typeDefinitions>

    <parameterSerializers>
        <serializers></serializers>
    </parameterSerializers>

    <!--The value of type attribute should be a type that implements
      IoC.Configuration.DiContainer.IDiManager-->
    <diManagers activeDiManagerName="Autofac">
        <!-- TODO:-->
        <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
                   assembly="ninject_ext">
            <!--
                  Use parameters element to specify constructor parameters,
                  if the type specified in 'type' attribute has non-default constructor.
                  -->
            <!--<parameters>
                  </parameters>-->
        </diManager>

        <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
                   assembly="autofac_ext">
        </diManager>
    </diManagers>

    <!--
      If settingsRequestor element is used, the type in type attribute should
      specify a type that implements IoC.Configuration.ISettingsRequestor.
      The implementation specifies a collection of required settings that should be present
      in settings element.
      Note, the type specified in type attribute is fully integrated into a dependency
      injection framework. In other words, constructor parameters will be injected using
      bindings specified in dependencyInjection element.
      -->

    <settings>
        <constructedValue name="DefaultAppData" typeRef="AppData">
            <injectedProperties>
                <object name="ApplicationId" typeRef="Guid" value="09E7ABD4-1BA1-4683-BEF5-EFA8266D7308"/>
                <string name="Name" value="Default Application"/>
            </injectedProperties>
        </constructedValue>

    </settings>

    <dependencyInjection>
        <modules>
            <!--<module type="IoC.Configuration.Tests.AutoService.AutoServiceTestsModule" />-->
        </modules>
        <services>

            <!--IoC.Configuration.Tests.ProxyService.Services.IAppManager will be resolved
            by resolving IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension.-->
            <proxyService type="IoC.Configuration.Tests.ProxyService.Services.IAppManager">
                <serviceToProxy type="IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension"/>
            </proxyService>

            <!--IoC.Configuration.Tests.ProxyService.Services.IAppManager2 will also be resolved to
                IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension.-->
            <proxyService type="IoC.Configuration.Tests.ProxyService.Services.IAppManager2">
                <serviceToProxy type="IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension"/>
            </proxyService>

            <!--
                AppManagerUser has a constructor with parameter of type IAppManager.
                Since we have a proxyService element that resolves IAppManager to IAppManager_Extension,
                the object injected into constructor will be resolved by resolving the service IAppManager_Extension.
                IAppManager_Extension is auto-implemented in autoGeneratedServices element, however, it
                can have regular implementation in code as well.
                -->
            <selfBoundService type="IoC.Configuration.Tests.ProxyService.Services.AppManagerUser" scope="singleton"/>

            <!--
                AppManagerUser2 has a constructor with parameter of type  IAppManager2.
                Since we have a proxyService element that resolves IAppManager2 to IAppManager_Extension,
                the object injected into will be resolved by resolving the service IAppManager_Extension.
                -->
            <selfBoundService type="IoC.Configuration.Tests.ProxyService.Services.AppManager2User" scope="singleton"/>

            <service type="IoC.Configuration.Tests.ProxyService.Services.IInterface1_Extension">
                <implementation type="IoC.Configuration.Tests.ProxyService.Services.Interface1_Extension_Impl1"
                                scope="singleton"/>
            </service>

            <!--IoC.Configuration.Tests.ProxyService.Services.IInterface1 will be resolved by
              resolving IoC.Configuration.Tests.ProxyService.Services.IInterface1_Extension.-->
            <proxyService type="IoC.Configuration.Tests.ProxyService.Services.IInterface1">
                <serviceToProxy type="IoC.Configuration.Tests.ProxyService.Services.IInterface1_Extension"/>
            </proxyService>

            <!--
                Interface1User has a constructor with parameter of type IInterface1.
                Since we have a proxyService element that resolves IInterface1 to IInterface1_Extension,
                the object injected into constructor will be resolved by resolving the service IInterface1_Extension.
                -->
            <selfBoundService type="IoC.Configuration.Tests.ProxyService.Services.Interface1User" scope="singleton"/>

            <!--System.Collections.Generic.List<System.Int32> will be bound to a list of three integers: 19, 2, 17-->
            <service typeRef="ListOfInt">
                <valueImplementation scope="singleton">
                    <collection>
                        <int32 value="19"/>
                        <int32 value="2"/>
                        <int32 value="17"/>
                    </collection>
                </valueImplementation>
            </service>

            <!--Resolving System.Collections.Generic.IEnumerable<System.Int32> will return the same value as resolving
                  System.Collections.Generic.List<System.Int32>-->
            <proxyService type="System.Collections.Generic.IEnumerable[System.Int32]">
                <serviceToProxy typeRef="ListOfInt"/>
            </proxyService>

            <!--Resolving System.Collections.Generic.IReadOnlyList<System.Int32> will return the same value as resolving
                  System.Collections.Generic.List<System.Int32>-->
            <proxyService type="System.Collections.Generic.IReadOnlyList[System.Int32]">
                <serviceToProxy typeRef="ListOfInt"/>
            </proxyService>

            <!--Resolving System.Collections.Generic.IList<System.Int32> will return the same value as resolving
                  System.Collections.Generic.List<System.Int32>-->
            <proxyService type="System.Collections.Generic.IList[System.Int32]">
                <serviceToProxy typeRef="ListOfInt"/>
            </proxyService>

            <!--START-Test binding an interface to the ame instance to which a self-bound class is bound-->
            <selfBoundService type="SharedServices.Implementations.Interface13_Impl1" scope="singleton" />

            <!--NOTE: Using proxyService allows us to bind
            SharedServices.Interfaces.IInterface13 to the same instance of SharedServices.Implementations.Interface13_Impl1 to which
            SharedServices.Implementations.Interface13_Impl1 was bound using selfBoundService element.

            If we used "implementation" element under service and specified a type SharedServices.Implementations.Interface13_Impl1
            instead of using "proxyService", then SharedServices.Interfaces.IInterface13 would have been
            bound to a different instance of SharedServices.Implementations.Interface13_Impl1. In other words resolving
            SharedServices.Implementations.Interface13_Impl1 and SharedServices.Interfaces.IInterface13 would have resulted in
            different instances of SharedServices.Implementations.Interface13_Impl1.
            Using "proxyService" element might be useful when we have module(s) that scan assemblies and self-binds
            non-abstract classes. In this cases we can use "proxyService" element if we want the interface
            specified in "proxyService" element to resolve to exactly the same value to which the self bound class is bound.
            -->
            <proxyService type="SharedServices.Interfaces.IInterface13">
                <serviceToProxy type="SharedServices.Implementations.Interface13_Impl1"/>
            </proxyService>

            <service type="SharedServices.Interfaces.IInterface14">
                <implementation type="SharedServices.Implementations.Interface14_Impl1" scope="singleton" />
            </service>

            <!--END-Test binding an interface to the ame instance to which a self-bound class is bound-->
        </services>

        <autoGeneratedServices>
            <!--The scope for autoService implementations is always singleton -->
            <!--IAppManager_Extension extends IAppManager, so can implement properties and method in both
              IAppManager and IAppManager_Extension
            -->
            <autoService interface="IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension">
                <!--  IAppData IAppManager.GetApp(System.Guid applicationId):-->
                <autoMethod name="GetApp"
                            returnTypeRef="IAppData"
                            reuseValue="true">
                    <methodSignature>
                        <object typeRef="Guid"/>
                    </methodSignature>

                    <if parameter1="3907D19A-E53C-4471-B1B1-A3E0C36482B6">
                        <constructedValue typeRef="AppData">
                            <injectedProperties>
                                <object name="ApplicationId" typeRef="Guid"
                                        value="3907D19A-E53C-4471-B1B1-A3E0C36482B6"/>
                                <string name="Name" value="App1"/>
                            </injectedProperties>
                        </constructedValue>
                    </if>

                    <if parameter1="09E7ABD4-1BA1-4683-BEF5-EFA8266D7308">
                        <constructedValue typeRef="AppData">
                            <injectedProperties>
                                <object name="ApplicationId" typeRef="Guid"
                                        value="09E7ABD4-1BA1-4683-BEF5-EFA8266D7308"/>
                                <string name="Name" value="App2"/>
                            </injectedProperties>
                        </constructedValue>
                    </if>

                    <default>
                        <settingValue settingName="DefaultAppData"/>
                    </default>
                </autoMethod>

                <!---bool IAppManager2.IsPublicApp(Guid applicationId):-->
                <autoMethod name="IsPublicApp" returnType="System.Boolean">
                    <methodSignature>
                        <object paramName="applicationId" typeRef="Guid"/>
                    </methodSignature>

                    <if parameter1="09E7ABD4-1BA1-4683-BEF5-EFA8266D7308">
                        <boolean value="true"/>
                    </if>

                    <default>
                        <boolean value="false"/>
                    </default>
                </autoMethod>

                <!-- IAppData IAppManager_Extension.DefaultApp { get; }-->
                <autoProperty name="DefaultApp" returnTypeRef="IAppData">
                    <settingValue settingName="DefaultAppData"/>
                </autoProperty>
            </autoService>
        </autoGeneratedServices>
    </dependencyInjection>

    <startupActions>

    </startupActions>

    <pluginsSetup>
        <pluginSetup plugin="Plugin1">
            <!--The type in pluginImplementation should be non-abstract class
                that implements IoC.Configuration.IPlugin and which has a public constructor-->
            <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
            </pluginImplementation>

            <settings>
                <int32 name="Int32Setting1" value="10"/>
                <string name="StringSetting1" value="Some text"/>
            </settings>

            <dependencyInjection>
                <modules>
                </modules>

                <services>
                    <service type="TestPluginAssembly1.Interfaces.IDemoProxyService_Extension">
                        <implementation type="TestPluginAssembly1.Implementations.DemoProxyService_Extension_Impl"
                                        scope="singleton"/>
                    </service>

                    <!--TestPluginAssembly1.Interfaces.IDemoProxyServicewill be resolved by
                        resolving TestPluginAssembly1.Interfaces.IDemoProxyService_Extension.-->
                    <proxyService type="TestPluginAssembly1.Interfaces.IDemoProxyService">
                        <serviceToProxy type="TestPluginAssembly1.Interfaces.IDemoProxyService_Extension"/>
                    </proxyService>

                    <!--
                    DemoProxyServiceUser has a constructor with parameter of type IDemoProxyService.
                    Since we have a proxyService element that resolves IDemoProxyService to IDemoProxyService_Extension,
                    the object injected into constructor will be resolved by resolving the service IDemoProxyService_Extension.
                    -->
                    <selfBoundService type="TestPluginAssembly1.Implementations.DemoProxyServiceUser"
                                      scope="singleton"/>
                </services>

                <autoGeneratedServices>

                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>

        <pluginSetup plugin="Plugin2">
            <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2" assembly="pluginassm2">
                <parameters>
                    <boolean name="param1" value="true"/>
                    <double name="param2" value="25.3"/>
                    <string name="param3" value="String value"/>
                </parameters>
            </pluginImplementation>
            <settings>
            </settings>
            <dependencyInjection>
                <modules>
                </modules>
                <services>
                </services>
                <autoGeneratedServices>
                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>

        <pluginSetup plugin="Plugin3">
            <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3" assembly="pluginassm3">

            </pluginImplementation>
            <settings>
            </settings>
            <dependencyInjection>
                <modules>
                </modules>
                <services>
                </services>
                <autoGeneratedServices>
                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>
    </pluginsSetup>
</iocConfiguration>

IoCConfiguration_valueImplementation.xml

This configuration file can be downloaded downloaded from IoCConfiguration_valueImplementation.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
<?xml version="1.0" encoding="utf-8"?>

<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->
<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

     <!--The application should have write permissions to path specified in appDataDir.
    This is where dynamically generated DLLs are saved.-->
     <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
     <appDataDir
       path="TestFiles\AutogeneratedDlls\DynamicFiles_ValueImplementationTests" />

     <plugins pluginsDirPath="TestFiles\PluginDlls">

             <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

             <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
             <plugin name="Plugin1" />
             <plugin name="Plugin2" enabled="true" />
             <plugin name="Plugin3" enabled="false" />
     </plugins>

     <additionalAssemblyProbingPaths>
             <probingPath
               path="TestFiles\ThirdPartyLibs" />
             <probingPath
               path="TestFiles\ContainerImplementations\Autofac" />
             <probingPath
               path="TestFiles\ContainerImplementations\Ninject" />
             <probingPath
               path="TestFiles\DynamicallyLoadedDlls" />
     </additionalAssemblyProbingPaths>

     <assemblies>
             <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

             <!--
             Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
             an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
             -->
             <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
             <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

             <assembly name="TestProjects.Modules" alias="modules" />

             <assembly name="TestProjects.DynamicallyLoadedAssembly1"
                               alias="dynamic1" />

             <assembly name="TestProjects.DynamicallyLoadedAssembly2"
                               alias="dynamic2" />

             <assembly name="TestProjects.TestPluginAssembly1"
                               alias="pluginassm1" plugin="Plugin1" />

             <assembly name="TestProjects.TestPluginAssembly2"
                               alias="pluginassm2" plugin="Plugin2" />

             <assembly name="TestProjects.TestPluginAssembly3"
                               alias="pluginassm3" plugin="Plugin3" />

             <assembly name="TestProjects.ModulesForPlugin1"
                               alias="modules_plugin1" plugin="Plugin1" />

             <assembly name="TestProjects.SharedServices" alias="shared_services" />

             <assembly name="IoC.Configuration.Tests" alias="tests" />
     </assemblies>

     <typeDefinitions>
             <typeDefinition alias="IAppInfo" type="IoC.Configuration.Tests.ValueImplementation.Services.IAppInfo" />
             <typeDefinition alias="AppInfo" type="IoC.Configuration.Tests.ValueImplementation.Services.AppInfo" />
     </typeDefinitions>

     <parameterSerializers>
             <serializers>
                     <parameterSerializer type="TestPluginAssembly1.Implementations.DoorSerializer" />
             </serializers>
     </parameterSerializers>

     <!--The value of type attribute should be a type that implements
    IoC.Configuration.DiContainer.IDiManager-->
     <diManagers activeDiManagerName="Autofac">
             <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
                                assembly="ninject_ext">
                     <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute has non-default constructor.
            -->
                     <!--<parameters>
            </parameters>-->
             </diManager>

             <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
                                assembly="autofac_ext">
             </diManager>
     </diManagers>

     <!--
    If settingsRequestor element is used, the type in type attribute should
    specify a type that implements IoC.Configuration.ISettingsRequestor.
    The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency
    injection framework. In other words, constructor parameters will be injected using
    bindings specified in dependencyInjection element.
    -->

     <settings>
             <int32 name="defaultAppId" value="38" />
             <string name="defaultAppDescription" value="Deafult App"/>
             <!--<constructedValue  name="defaultAppInfo" typeRef="AppInfo">
      <parameters>
        <int32 name="appId" value="37"/>
      </parameters>
    </constructedValue>-->

     </settings>

     <dependencyInjection>
             <modules>
                     <!--<module type="IoC.Configuration.Tests.AutoService.AutoServiceTestsModule" />-->
                     <module type="IoC.Configuration.Tests.ValueImplementation.Module1" />
             </modules>
             <services>
                     <!--int value is bound to the value of setting defaultAppId.-->
                     <service type="System.Int32">
                             <valueImplementation scope="singleton">
                                     <settingValue settingName="defaultAppId"/>
                             </valueImplementation>
                     </service>


                     <!--Service IAppInfo is bound to AppInfo constructed using constructedValue element.-->
                     <service typeRef="IAppInfo">
                             <valueImplementation scope="transient">
                                     <constructedValue typeRef="AppInfo">
                                             <parameters>
                                                     <settingValue name="appId" settingName="defaultAppId" />
                                             </parameters>
                                     </constructedValue>
                             </valueImplementation>
                     </service>

                     <!--System.Double value is bound to 3.5.-->
                     <service type="System.Double">
                             <valueImplementation scope="singleton">
                                     <!--object elements value is initialized by a serializer of type OROptimizer.Serializer.ITypeBasedSimpleSerializer
          that can be registered in section parameterSerializers.
          IoC.Configuration provides number of default serializers for some types.
          The out of the box serializer for System.Double is OROptimizer.Serializer.TypeBasedSimpleSerializerDouble which is available
          in Nuget package OROptimizer.Shared.
          -->
                                     <object type="System.Double" value="3.5"/>
                             </valueImplementation>
                     </service>

                     <!--Examples of using classMember element in valueImplementation-->
                     <service type="IoC.Configuration.Tests.ValueImplementation.Services.IDbConnectionProvider">
                             <implementation type="IoC.Configuration.Tests.ValueImplementation.Services.DbConnectionProvider" scope="singleton">
                                     <parameters>
                                             <string name="serverName" value="SqlServer1"/>
                                             <string name="databaseName" value="Db1"/>
                                             <string name="userName" value="restrictedUser"/>
                                             <string name="password" value="safePassword123"/>
                                     </parameters>
                             </implementation>
                     </service>

                     <!--Type SharedServices.Interfaces.IDbConnection will be bound to a vlue returned by call to
      IoC.Configuration.Tests.ValueImplementation.Services.IDbConnectionProvider.GetDbConnection().
      Since IDbConnectionProvider.GetDbConnection() is non-static, an instance of IDbConnectionProvider will be resolved
      from DI container, and method GetDbConnection() will be called using the resolved instance
      -->
                     <service type="SharedServices.Interfaces.IDbConnection">
                             <valueImplementation scope="transient">
                                     <classMember class="IoC.Configuration.Tests.ValueImplementation.Services.IDbConnectionProvider" memberName="GetDbConnection"/>
                             </valueImplementation>
                     </service>

                     <service type="SharedServices.Interfaces.IActionValidator">
                             <valueImplementation scope="transient">
                                     <classMember class="IoC.Configuration.Tests.ValueImplementation.Services.StaticMethods" memberName="GetActionValidator"/>
                             </valueImplementation>
                     </service>

                     <!--Service IReadOnlyList<IoC.Configuration.Tests.ValueImplementation.Services.IAppInfo> is bound to a collection
                     specified in valueImplementation element.-->
                     <service type="System.Collections.Generic.IReadOnlyList[IoC.Configuration.Tests.ValueImplementation.Services.IAppInfo]">
                             <valueImplementation scope="singleton" >
                                     <collection>
                                             <constructedValue typeRef="AppInfo">
                                                     <parameters>
                                                             <int32 name="paramId" value="1"/>
                                                     </parameters>
                                             </constructedValue>

                                             <constructedValue typeRef="AppInfo">
                                                     <parameters>
                                                             <int32 name="paramId" value="2"/>
                                                     </parameters>
                                             </constructedValue>
                                     </collection>
                             </valueImplementation>
                     </service>

                     <!--
                     The service below will be ignored, since registerIfNotRegistered is true, and we already registered a binding for
                     System.Collections.Generic.List<IoC.Configuration.Tests.ValueImplementation.Services.IAppInfo> in
                     IoC.Configuration.Tests.ValueImplementation.Module1.
                     -->
                     <service type="System.Collections.Generic.List[IoC.Configuration.Tests.ValueImplementation.Services.IAppInfo]"
                                      registerIfNotRegistered="true">
                             <valueImplementation scope="singleton" >
                                     <collection>
                                             <constructedValue typeRef="AppInfo">
                                                     <parameters>
                                                             <int32 name="paramId" value="15"/>
                                                     </parameters>
                                             </constructedValue>
                                     </collection>
                             </valueImplementation>
                     </service>
             </services>

             <autoGeneratedServices>
                     <!--The scope for autoService implementations is always singleton -->

             </autoGeneratedServices>
     </dependencyInjection>

     <startupActions>

     </startupActions>

     <pluginsSetup>
             <pluginSetup plugin="Plugin1">
                     <!--The type in pluginImplementation should be non-abstract class
                that implements IoC.Configuration.IPlugin and which has a public constructor-->
                     <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
                     </pluginImplementation>

                     <settings>
                             <int32 name="Int32Setting1" value="10"/>
                             <string name="StringSetting1" value="Some text"/>
                     </settings>

                     <dependencyInjection>
                             <modules>
                             </modules>

                             <services>
                                     <service type="System.Collections.Generic.IReadOnlyList[TestPluginAssembly1.Interfaces.IDoor]">
                                             <valueImplementation scope="singleton">
                                                     <collection>
                                                             <object type="TestPluginAssembly1.Interfaces.IDoor" value="4359924‬, 80.3"/>
                                                             <constructedValue type="TestPluginAssembly1.Implementations.Door">
                                                                     <parameters>
                                                                             <int32 name="color" value="4359934"/>
                                                                             <double name="height" value="85.2" />
                                                                     </parameters>
                                                             </constructedValue>
                                                     </collection>
                                             </valueImplementation>
                                     </service>
                             </services>

                             <autoGeneratedServices>

                             </autoGeneratedServices>
                     </dependencyInjection>
             </pluginSetup>

             <pluginSetup plugin="Plugin2">
                     <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2" assembly="pluginassm2">
                             <parameters>
                                     <boolean name="param1" value="true" />
                                     <double name="param2" value="25.3" />
                                     <string name="param3" value="String value" />
                             </parameters>
                     </pluginImplementation>
                     <settings>
                     </settings>
                     <dependencyInjection>
                             <modules>
                             </modules>
                             <services>
                             </services>
                             <autoGeneratedServices>
                             </autoGeneratedServices>
                     </dependencyInjection>
             </pluginSetup>

             <pluginSetup plugin="Plugin3">
                     <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3" assembly="pluginassm3">

                     </pluginImplementation>
                     <settings>
                     </settings>
                     <dependencyInjection>
                             <modules>
                             </modules>
                             <services>
                             </services>
                             <autoGeneratedServices>
                             </autoGeneratedServices>
                     </dependencyInjection>
             </pluginSetup>
     </pluginsSetup>
</iocConfiguration>

IoCConfiguration_collection.xml

This configuration file can be downloaded downloaded from IoCConfiguration_collection.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
<?xml version="1.0" encoding="utf-8"?>

<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
      xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
      xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

  <!--The application should have write permissions to path specified in appDataDir.
    This is where dynamically generated DLLs are saved.-->
  <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
      IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
      IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
  <appDataDir
    path="TestFiles\AutogeneratedDlls\DynamicFiles_CollectionTests" />

  <plugins pluginsDirPath="TestFiles\PluginDlls">

    <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

    <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
    <plugin name="Plugin1" />
    <plugin name="Plugin2" />
    <plugin name="Plugin3" enabled="false" />
  </plugins>

  <additionalAssemblyProbingPaths>
    <probingPath
      path="TestFiles\ThirdPartyLibs" />
    <probingPath
      path="TestFiles\ContainerImplementations\Autofac" />
    <probingPath
      path="TestFiles\ContainerImplementations\Ninject" />
    <probingPath
      path="TestFiles\DynamicallyLoadedDlls" />
  </additionalAssemblyProbingPaths>

  <assemblies>
    <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

    <!--
    Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
    an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
    -->
    <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
    <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

    <assembly name="TestProjects.Modules" alias="modules" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly1"
              alias="dynamic1" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly2"
              alias="dynamic2" />

    <assembly name="TestProjects.TestPluginAssembly1"
              alias="pluginassm1" plugin="Plugin1" />

    <assembly name="TestProjects.ModulesForPlugin1"
              alias="modules_plugin1" plugin="Plugin1" />

    <assembly name="TestProjects.TestPluginAssembly2"
              alias="pluginassm2" plugin="Plugin2" />

    <assembly name="TestProjects.TestPluginAssembly3"
              alias="pluginassm3" plugin="Plugin3" />

    <assembly name="TestProjects.SharedServices" alias="shared_services" />

    <assembly name="IoC.Configuration.Tests" alias="tests" />
  </assemblies>

  <typeDefinitions>
    <typeDefinition alias="IInterface1" type="SharedServices.Interfaces.IInterface1"></typeDefinition>
    <typeDefinition alias="Interface1_Impl" type="IoC.Configuration.Tests.Collection.Services.Interface1_Impl"></typeDefinition>
  </typeDefinitions>
  <parameterSerializers>
    <!--
        Use parameters element to specify constructor parameters, if the type specified in 'serializerAggregatorType' attribute
        has non-default constructor.
        -->
    <!--<parameters>
        </parameters>-->
    <serializers></serializers>
  </parameterSerializers>

  <!--The value of type attribute should be a type that implements
    IoC.Configuration.DiContainer.IDiManager-->
  <diManagers activeDiManagerName="Autofac">
    <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
               assembly="ninject_ext">
      <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute has non-default constructor.
            -->
      <!--<parameters>
      </parameters>-->
    </diManager>

    <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
               assembly="autofac_ext">
    </diManager>
  </diManagers>

  <!--
    If settingsRequestor element is used, the type in type attribute should
    specify a type that implements IoC.Configuration.ISettingsRequestor.
    The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency
    injection framework. In other words, constructor parameters will be injected using
    bindings specified in dependencyInjection element.
    -->

  <settings>
    <constructedValue name="DefaultDBConnection" type="SharedServices.Implementations.SqliteDbConnection"
                      assembly="shared_services">
      <parameters>
        <string name="filePath" value="c:\SQLiteFiles\MySqliteDb.sqlite"/>
      </parameters>
    </constructedValue>

    <constructedValue name="DefaultInterface1Value" typeRef="Interface1_Impl">
      <parameters>
        <int32 name="param1" value="21"/>
      </parameters>
    </constructedValue>

    <constructedValue name="Collections" type="IoC.Configuration.Tests.Collection.Services.DemoCollectionInjection">
      <parameters>
        <!--Demo of injecting a collection into a constructor of DemoCollectionInjection in constructedValue element-->
        <collection name="intValues" collectionType="readOnlyList" itemType="System.Int32">
          <int32 value="17"/>
          <int32 value="14"/>
        </collection>
      </parameters>
      <injectedProperties>
        <!--Demo of injecting a collection into a property of DemoCollectionInjection in constructedValue element.-->
        <collection name="Texts" collectionType="readOnlyList" itemType="System.String">
          <string value="Microsoft"/>
          <string value="Google"/>
          <string value="Amazon"/>
        </collection>
      </injectedProperties>
    </constructedValue>
  </settings>

  <dependencyInjection>
    <modules>
      <module type="IoC.Configuration.Tests.Collection.Module1">
        <parameters>
          <collection name="values" collectionType="enumerable" itemType="System.Int32">
            <int32 value="5"/>
            <int32 value="7"/>
          </collection>
        </parameters>

      </module>
    </modules>
    <services>
      <service type="SharedServices.Interfaces.IInterface1">
        <implementation type="IoC.Configuration.Tests.Collection.Services.Interface1_Impl" scope="singleton">
          <parameters>
            <int32 name="param1" value="37"/>
          </parameters>
        </implementation>
      </service>

      <!--Demo of collection element used as an implementation for a service of collection type.-->
      <service type="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IDbConnection]">
        <valueImplementation scope="singleton">
          <collection>
            <settingValue settingName="DefaultDBConnection"/>
            <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
              <parameters>
                <string name="serverName" value="SQLSERVER2012"/>
                <string name="databaseName" value="DB1"/>
                <string name="userName" value="user1"/>
                <string name="password" value="password123"/>
              </parameters>
            </constructedValue>
            <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
              <parameters>
                <string name="serverName" value="SQLSERVER2016"/>
                <string name="databaseName" value="DB2"/>
                <string name="userName" value="user2"/>
                <string name="password" value="password456"/>
              </parameters>
            </constructedValue>

            <!--This value will be added to collection since Plugin1 is enabled-->
            <constructedValue type="TestPluginAssembly1.Implementations.MySqlDbConnection">
              <parameters>
                <string name="connectionString" value="user=User1;password=123"/>
              </parameters>
            </constructedValue>

            <!--This value will not be added to collection since Plugin3 is disabled-->
            <constructedValue type="TestPluginAssembly3.Implementations.OracleDbConnection" >
              <parameters>
                <string name="connectionString" value="user=User1;password=123"/>
              </parameters>
            </constructedValue>
          </collection>
        </valueImplementation>
      </service>

      <!--Demo of collection element used as an implementation for a service of array type.-->
      <!--The service type below is similar to C# type IoC.Configuration.Tests.Collection.Services.TestLocalTypesClass.IInterface1[]-->
      <service type="IoC.Configuration.Tests.Collection.Services.TestLocalTypesClass.IInterface1#">
        <valueImplementation scope="transient">
          <collection>
            <constructedValue type="IoC.Configuration.Tests.Collection.Services.TestLocalTypesClass.Interface1_Impl1">
              <parameters>
                <int32 name="value" value="13"/>
              </parameters>
            </constructedValue>
            <constructedValue type="IoC.Configuration.Tests.Collection.Services.TestLocalTypesClass.Interface1_Impl1">
              <parameters>
                <int32 name="value" value="17"/>
              </parameters>
            </constructedValue>
          </collection>
        </valueImplementation>
      </service>

      <selfBoundService type="IoC.Configuration.Tests.Collection.Services.CollectionsTestClass1" scope="singleton" >
        <parameters>
          <!--Demo of collection element used as a constructor parameter.-->
          <collection name="readOnlyListParam" collectionType="readOnlyList" itemType="System.Int32">
            <int32 value="17"/>
            <int32 value="24"/>
            <int32 value="27"/>
          </collection>

          <!--Demo of collection element used as a constructor parameter.-->
          <collection name="arrayParam" collectionType="array" itemTypeRef="IInterface1">
            <injectedObject typeRef="IInterface1"/>
            <constructedValue typeRef="Interface1_Impl">
              <parameters>
                <int32 name="param1" value="29"/>
              </parameters>
            </constructedValue>
          </collection>
        </parameters>
        <injectedProperties>
          <!--Demo of collection element used to initialize the value of injected property.-->
          <collection name="EnumerableValues" collectionType="enumerable" itemType="SharedServices.Interfaces.IInterface1" >
            <constructedValue typeRef="Interface1_Impl">
              <parameters>
                <int32 name="param1" value="18"/>
              </parameters>
            </constructedValue>
            <settingValue settingName="DefaultInterface1Value"/>
            <injectedObject typeRef="IInterface1"/>
          </collection>

          <!--Demo of collection element used to initialize the value of injected property.-->
          <collection name="ListValues" collectionType="list" itemTypeRef="IInterface1">
            <injectedObject typeRef="IInterface1"/>
            <settingValue settingName="DefaultInterface1Value"/>
            <constructedValue typeRef="Interface1_Impl">
              <parameters>
                <int32 name="param1" value="139"/>
              </parameters>
            </constructedValue>
          </collection>
        </injectedProperties>
      </selfBoundService>
    </services>
    <autoGeneratedServices>
      <!--Demo of collection element used in auto-implemented method and property return values.-->
      <autoService interface="IoC.Configuration.Tests.Collection.Services.IAutoService1">
        <autoMethod name="GetAllActionIds" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]">
          <methodSignature>
            <int32 paramName="appId"/>
          </methodSignature>
          <if parameter1="3">
            <collection>
              <int32 value="27"/>
              <int32 value="17"/>
            </collection>
          </if>
          <default>
            <collection>
              <int32 value="13"/>
              <int32 value="27"/>
              <int32 value="17"/>
            </collection>
          </default>
        </autoMethod>
      </autoService>
    </autoGeneratedServices>
  </dependencyInjection>

  <startupActions>

  </startupActions>

  <pluginsSetup>
    <pluginSetup plugin="Plugin1">
      <!--The type in pluginImplementation should be non-abstract class
                that implements IoC.Configuration.IPlugin and which has a public constructor-->
      <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
      </pluginImplementation>

      <settings>
        <int32 name="Int32Setting1" value="10"/>
        <string name="StringSetting1" value="Some text"/>
      </settings>

      <dependencyInjection>
        <modules>

        </modules>
        <services>

        </services>
        <autoGeneratedServices>

        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>

    <pluginSetup plugin="Plugin2">
      <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2" assembly="pluginassm2">
        <parameters>
          <boolean name="param1" value="true" />
          <double name="param2" value="25.3" />
          <string name="param3" value="String value" />
        </parameters>
      </pluginImplementation>
      <settings>
      </settings>
      <dependencyInjection>
        <modules>
        </modules>
        <services>
        </services>
        <autoGeneratedServices>
        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>

    <pluginSetup plugin="Plugin3">
      <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3" assembly="pluginassm3">

      </pluginImplementation>
      <settings>
      </settings>
      <dependencyInjection>
        <modules>
        </modules>
        <services>
        </services>
        <autoGeneratedServices>
        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>
  </pluginsSetup>
</iocConfiguration>

IoCConfiguration_constructedValue.xml

This configuration file can be downloaded downloaded from IoCConfiguration_constructedValue.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
<?xml version="1.0" encoding="utf-8"?>

<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory. constructed
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

  <!--The application should have write permissions to path specified in appDataDir.
    This is where dynamically generated DLLs are saved.-->
  <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
  <appDataDir
    path="TestFiles\AutogeneratedDlls\DynamicFiles_constructedValueTests" />

  <plugins pluginsDirPath="TestFiles\PluginDlls">

    <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

    <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
  </plugins>

  <additionalAssemblyProbingPaths>
    <probingPath
      path="TestFiles\ThirdPartyLibs" />
    <probingPath
      path="TestFiles\ContainerImplementations\Autofac" />
    <probingPath
      path="TestFiles\ContainerImplementations\Ninject" />
    <probingPath
      path="TestFiles\DynamicallyLoadedDlls" />
  </additionalAssemblyProbingPaths>

  <assemblies>
    <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

    <!--
    Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
    an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
    -->
    <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
    <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

    <assembly name="TestProjects.Modules" alias="modules" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly1"
              alias="dynamic1" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly2"
              alias="dynamic2" />

    <assembly name="TestProjects.SharedServices" alias="shared_services" />

    <assembly name="IoC.Configuration.Tests" alias="tests" />
  </assemblies>

  <typeDefinitions>
    <typeDefinition alias="IAppInfo" type="IoC.Configuration.Tests.ConstructedValue.Services.IAppInfo" />
    <typeDefinition alias="AppInfo" type="IoC.Configuration.Tests.ConstructedValue.Services.AppInfo" />
  </typeDefinitions>

  <parameterSerializers>
    <serializers>
      <!--Serializer IoC.Configuration.Tests.ConstructedValue.Services.AppInfoSerializer will be used to de-serialize value
      provided in element <object> into instance of type IoC.Configuration.Tests.ConstructedValue.Services.AppInfo-->
      <parameterSerializer type="IoC.Configuration.Tests.ConstructedValue.Services.AppInfoSerializer">
        <parameters>
          <!--Demo of using constructedValue to inject constructor parameter value into parameter serializer.-->
          <constructedValue name="appDescriptionFormatter" type="IoC.Configuration.Tests.ConstructedValue.Services.AppDescriptionFormatter">
            <parameters>
              <string name="prefixToAddToDescription" value="AppData::"/>
            </parameters>
            <injectedProperties>
              <string name="PostfixToAddToDescription" value="::AppDataEnd"/>
            </injectedProperties>
          </constructedValue>
        </parameters>
      </parameterSerializer>
    </serializers>
  </parameterSerializers>

  <!--The value of type attribute should be a type that implements
    IoC.Configuration.DiContainer.IDiManager-->
  <diManagers activeDiManagerName="Autofac">
    <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
               assembly="ninject_ext">
      <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute has non-default constructor.
            -->
      <!--<parameters>
            </parameters>-->
    </diManager>

    <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
               assembly="autofac_ext">
    </diManager>
  </diManagers>

  <!--
    If settingsRequestor element is used, the type in type attribute should
    specify a type that implements IoC.Configuration.ISettingsRequestor.
    The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency
    injection framework. In other words, constructor parameters will be injected using
    bindings specified in dependencyInjection element.
    -->

  <settings>
    <object name="App1" typeRef="IAppInfo" value="1, App 1"/>

    <!--Demo of constructedValue in settings element. -->
    <constructedValue name="App2" typeRef="AppInfo" >
      <parameters>
        <int32 name="Id" value="2"/>
      </parameters>
      <injectedProperties>
        <string name="Description" value="App 2"/>
      </injectedProperties>
    </constructedValue>

    <!--Demo of constructedValue used as a parameter value in another constructedValue.
    Constructing DecoratedAppInfo setting below is similar to creating an instance of AppInfoDecorator using the following C# code:
    new AppInfoDecorator(new AppInfoDecorator(new AppInfo(25, "App 25")))
    -->
    <constructedValue name="DecoratedAppInfo" type="IoC.Configuration.Tests.ConstructedValue.Services.AppInfoDecorator">
      <parameters>
        <constructedValue name="appInfo" type="IoC.Configuration.Tests.ConstructedValue.Services.AppInfoDecorator">
          <parameters>
            <constructedValue name="appInfo" typeRef="AppInfo">
              <parameters>
                <int32 name="id" value="25"/>
              </parameters>
              <injectedProperties>
                <string name="Description" value="App 25"/>
              </injectedProperties>
            </constructedValue>
          </parameters>
        </constructedValue>
      </parameters>
    </constructedValue>
  </settings>

  <dependencyInjection>
    <modules>
      <module type="IoC.Configuration.Tests.ConstructedValue.Module1">
        <parameters>
          <!--Demo of constructedValue to inject constructor parameter and property into module. -->
          <constructedValue name="appInfo" typeRef="AppInfo">
            <parameters>
              <int32 name="id" value="3"/>
            </parameters>
            <injectedProperties>
              <string name="Description" value="App 3"/>
            </injectedProperties>
          </constructedValue>
        </parameters>
      </module>
    </modules>

    <services>
      <service typeRef="IAppInfo">
        <valueImplementation scope="singleton">

          <!--Demo of constructedValue to provide an implementation for a service under valueImplementation element.-->
          <constructedValue typeRef="AppInfo">
            <parameters>
              <int32 name="id" value="8"/>
            </parameters>
            <injectedProperties>
              <string name="Description" value="App 8"/>
            </injectedProperties>
          </constructedValue>
        </valueImplementation>
      </service>

      <service type="System.Collections.Generic.IReadOnlyList[IoC.Configuration.Tests.ConstructedValue.Services.IAppInfo]">
        <valueImplementation scope="singleton">
          <collection>
            <!--Demo of constructedValue in collection-->
            <constructedValue typeRef="AppInfo">
              <parameters>
                <int32 name="id" value="10"/>
              </parameters>
              <injectedProperties>
                <string name="Description" value="App 10"/>
              </injectedProperties>
            </constructedValue>

            <settingValue settingName="App1"/>
          </collection>
        </valueImplementation>

      </service>

    </services>

    <autoGeneratedServices>
      <!--The scope for autoService implementations is always singleton -->

      <autoService interface="IoC.Configuration.Tests.ConstructedValue.Services.IAppInfoFactory">
        <autoProperty name="DefaultAppInfo" returnTypeRef="IAppInfo">

          <!--Demo of constructedValue in autoProperty-->
          <constructedValue typeRef="AppInfo" >
            <parameters>
              <int32 name="id" value="11"/>
            </parameters>
            <injectedProperties>
              <string name="Description" value="App 11"/>
            </injectedProperties>
          </constructedValue>
        </autoProperty>

        <!--Demo of constructedValue in autoMethod-->
        <autoMethod name="CreateAppInfo" returnTypeRef="IAppInfo">
          <default>
            <constructedValue  typeRef="AppInfo" >
              <parameters>
                <int32 name="id" value="12"/>
              </parameters>
              <injectedProperties>
                <string name="Description" value="App 12"/>
              </injectedProperties>
            </constructedValue>
          </default>
        </autoMethod>
      </autoService>

    </autoGeneratedServices>
  </dependencyInjection>

  <startupActions>
    <startupAction type="IoC.Configuration.Tests.ConstructedValue.Services.StartupAction1">
      <parameters>
        <constructedValue name="appInfo" typeRef="AppInfo">
          <parameters>
            <int32 name="id" value="9"/>
          </parameters>
          <injectedProperties>
            <string name="Description" value="App 9"/>
          </injectedProperties>
        </constructedValue>
      </parameters>
    </startupAction>

  </startupActions>

  <pluginsSetup>
  </pluginsSetup>
</iocConfiguration>

IoCConfiguration_classMember.xml

This configuration file can be downloaded downloaded from IoCConfiguration_classMember.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
<?xml version="1.0" encoding="utf-8"?>

<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

    <!--The application should have write permissions to path specified in appDataDir.
      This is where dynamically generated DLLs are saved.-->
    <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
    <appDataDir
            path="TestFiles\AutogeneratedDlls\DynamicFiles_ClassMemberTests"/>

    <plugins
            pluginsDirPath="TestFiles\PluginDlls">

        <!--
            Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
            The plugin folders will be included in assembly resolution mechanism.
            -->

        <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
        <plugin name="Plugin1"/>
        <plugin name="Plugin2" enabled="true"/>
        <plugin name="Plugin3" enabled="false"/>
    </plugins>

    <additionalAssemblyProbingPaths>
        <probingPath
                path="TestFiles\ThirdPartyLibs"/>
        <probingPath
                path="TestFiles\ContainerImplementations\Autofac"/>
        <probingPath
                path="TestFiles\ContainerImplementations\Ninject"/>
        <probingPath
                path="TestFiles\DynamicallyLoadedDlls"/>
    </additionalAssemblyProbingPaths>

    <assemblies>
        <!--Assemblies should be in one of the following locations:
            1) Executable's folder
            2) In folder specified in additionalAssemblyProbingPaths element.
            3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

        <!--
        Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
        an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
        -->
        <assembly name="IoC.Configuration.Autofac" alias="autofac_ext"/>
        <assembly name="IoC.Configuration.Ninject" alias="ninject_ext"/>

        <assembly name="TestProjects.Modules" alias="modules"/>

        <assembly name="TestProjects.DynamicallyLoadedAssembly1"
                  alias="dynamic1"/>

        <assembly name="TestProjects.DynamicallyLoadedAssembly2"
                  alias="dynamic2"/>

        <assembly name="TestProjects.TestPluginAssembly1"
                  alias="pluginassm1" plugin="Plugin1"/>

        <assembly name="TestProjects.TestPluginAssembly2"
                  alias="pluginassm2" plugin="Plugin2"/>

        <assembly name="TestProjects.TestPluginAssembly3"
                  alias="pluginassm3" plugin="Plugin3"/>

        <assembly name="TestProjects.ModulesForPlugin1"
                  alias="modules_plugin1" plugin="Plugin1"/>

        <assembly name="TestProjects.SharedServices" alias="shared_services"/>

        <assembly name="IoC.Configuration.Tests" alias="tests"/>
    </assemblies>

    <typeDefinitions>
        <typeDefinition alias="ConstAndStaticAppIds"
                        type="IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds"/>
        <typeDefinition alias="IAppIds" type="IoC.Configuration.Tests.ClassMember.Services.IAppIds"/>
        <typeDefinition alias="AppTypes" type="IoC.Configuration.Tests.ClassMember.Services.AppTypes"/>
        <typeDefinition alias="AppInfo" type="IoC.Configuration.Tests.ClassMember.Services.AppInfo"/>
        <typeDefinition alias="StaticMethodsWithParameters"
                        type="IoC.Configuration.Tests.ClassMember.Services.StaticMethodsWithParameters"/>
    </typeDefinitions>

    <parameterSerializers>
        <serializers></serializers>
    </parameterSerializers>

    <!--The value of type attribute should be a type that implements
      IoC.Configuration.DiContainer.IDiManager-->
    <diManagers activeDiManagerName="Autofac">
        <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
                   assembly="ninject_ext">
            <!--
                  Use parameters element to specify constructor parameters,
                  if the type specified in 'type' attribute has non-default constructor.
                  -->
            <!--<parameters>
                  </parameters>-->
        </diManager>

        <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
                   assembly="autofac_ext">
        </diManager>
    </diManagers>

    <!--
      If settingsRequestor element is used, the type in type attribute should
      specify a type that implements IoC.Configuration.ISettingsRequestor.
      The implementation specifies a collection of required settings that should be present
      in settings element.
      Note, the type specified in type attribute is fully integrated into a dependency
      injection framework. In other words, constructor parameters will be injected using
      bindings specified in dependencyInjection element.
      -->

    <settings>

    </settings>

    <dependencyInjection>
        <modules>
            <!--<module type="IoC.Configuration.Tests.AutoService.AutoServiceTestsModule" />-->
            <module type="IoC.Configuration.Tests.ClassMember.Module1">
                <parameters>
                    <classMember name="param1" classRef="ConstAndStaticAppIds" memberName="DefaultAppId"/>
                    <classMember name="param2" classRef="StaticMethodsWithParameters" memberName="GetString">
                        <parameters>
                            <int32 name="intParam" value="5"/>
                            <string name="strParam" value="Value 1"/>
                        </parameters>
                    </classMember>
                </parameters>
            </module>
        </modules>
        <services>
            <service type="System.Int32">
                <valueImplementation scope="singleton">
                    <!--Example of classMember in valueImplementation. Since IAppIds.DefaultAppId is non-static,
                    IAppIds will be resolved from dependency injection container, and the value of property DefaultAppId of
                    resolved object will be bound to System.Int32
                    -->
                    <classMember classRef="IAppIds" memberName="DefaultAppId"/>

                </valueImplementation>
            </service>

            <!--<service type="System.String">
               <valueImplementation scope="singleton">
                  <object type="System.String" value="Test"/>
               </valueImplementation>
            </service>-->
            <service type="System.String">
                <valueImplementation scope="singleton">
                    <!--Example of classMember in valueImplementation. Since IAppIds.DefaultAppDescription is non-static,
                        IAppIds will be resolved from dependency injection container, and the value of property DefaultAppDescription of
                        resolved object will be bound to System.Int32
                    -->
                    <classMember classRef="IAppIds" memberName="DefaultAppDescription"/>
                   <!-- <object type="System.String" value="Test" />-->
                </valueImplementation>
            </service>


            <service type="IoC.Configuration.Tests.ClassMember.Services.IAppInfo">
                <!--The DI will try to construct IoC.Configuration.Tests.ClassMember.Services.AppInfo using the constructor
                with max number of parameters: AppInfo(int appId, string appDescription).
                Since we bound System.Int32, and System.String to IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId,
                and IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppDescription, the values of injected
                appId and appDescription will be IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId and
                IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppDescription.
                -->
                <implementation typeRef="AppInfo" scope="singleton">
                </implementation>
            </service>

            <service type="System.Collections.Generic.IReadOnlyList[System.Int32]">
                <valueImplementation scope="singleton">
                    <collection>
                        <!--Demo of classMember in collection element.-->
                        <classMember classRef="ConstAndStaticAppIds" memberName="AppId1"/>
                        <classMember classRef="IAppIds" memberName="DefaultAppId"/>
                    </collection>
                </valueImplementation>
            </service>

            <service type="IoC.Configuration.Tests.ClassMember.Services.IAppInfoFactory">
                <implementation type="IoC.Configuration.Tests.ClassMember.Services.AppInfoFactory" scope="singleton"/>
            </service>
        </services>

        <autoGeneratedServices>

            <!--The scope for autoService implementations is always singleton -->
            <autoService interfaceRef="IAppIds">
                <autoProperty name="DefaultAppId" returnType="System.Int32">
                    <!--Example of using classMember attribute in auto property.-->
                    <classMember class="System.Int32" memberName="MaxValue"/>
                </autoProperty>

                <autoProperty name="DefaultAppDescription" returnType="System.String">
                    <!--Example of using classMember attribute in auto property.-->
                    <classMember classRef="ConstAndStaticAppIds" memberName="DefaultAppDescription"/>
                </autoProperty>
            </autoService>

            <autoService interface="IoC.Configuration.Tests.ClassMember.Services.IAppInfos">
                <autoProperty name="AllAppInfos"
                              returnType="System.Collections.Generic.IReadOnlyList[IoC.Configuration.Tests.ClassMember.Services.IAppInfo]">
                    <collection>
                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--Property IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId is non-static, therefore
                                IoC.Configuration.Tests.ClassMember.Services.IAppIds will be resolved from dependency injection container,
                                and the value of property DefaultAppId in resolved object will be used as parameter value appId-->
                                <classMember name="appId" classRef="IAppIds" memberName="DefaultAppId"/>
                            </parameters>
                            <injectedProperties>
                                <!--Property IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId is non-static, therefore
                                IoC.Configuration.Tests.ClassMember.Services.IAppIds will be resolved from dependency injection container,
                                and the value of property DefaultAppId in resolved object will be used as parameter value appId-->
                                <classMember name="AppDescription" classRef="IAppIds"
                                             memberName="DefaultAppDescription"/>
                            </injectedProperties>
                        </constructedValue>

                        <!--
                        An example of calling a non static factory method to create an instance of IAppInfo.
                        Since method IoC.Configuration.Tests.ClassMember.Services.IAppInfoFactory.CreateAppInfo(appId, appDescription)
                        is non-static, an instance of IAppInfoFactory will be resolved using the DI container.
                        Also, since IAppInfoFactory is an interface, a binding for IAppInfoFactory should be configured in configuration
                        file or in some module.
                        -->
                        <classMember class="IoC.Configuration.Tests.ClassMember.Services.IAppInfoFactory"
                                     memberName="CreateAppInfo">
                            <parameters>
                                <int32 name="appId" value="1258"/>
                                <string name="appDescription" value="App info created with non-static method call."/>
                            </parameters>
                        </classMember>

                        <!--
                        An example of calling a static factory method to create an instance of IAppInfo.
                        -->
                        <classMember class="IoC.Configuration.Tests.ClassMember.Services.StaticAppInfoFactory"
                                     memberName="CreateAppInfo">
                            <parameters>
                                <int32 name="appId" value="1259"/>
                                <string name="appDescription" value="App info created with static method call."/>
                            </parameters>
                        </classMember>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--Method IoC.Configuration.Tests.ClassMember.Services.IAppIds.GetAppId() is non-static, therefore
                                IoC.Configuration.Tests.ClassMember.Services.IAppIds will be resolved from dependency injection container,
                                and the value returned by method IAppIds.GetAppId() will be used as parameter value appId-->
                                <classMember name="appId" classRef="IAppIds" memberName="GetAppId"/>
                            </parameters>
                        </constructedValue>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--Variable IoC.Configuration.Tests.ClassMember.Services.AppIdVars.NonStaticAppIdVar is non-static/non-constant, therefore
                                IoC.Configuration.Tests.ClassMember.Services.AppIdVars will be resolved from dependency injection container,
                                and the value variable NonStaticAppIdVarin resolved object will be used as parameter value appId
                                NOTE, no need to add a self bound service for IoC.Configuration.Tests.ClassMember.Services.AppIdVars, since
                                IoC.Configuration will generated one.
                                -->
                                <classMember name="appId" class="IoC.Configuration.Tests.ClassMember.Services.AppIdVars"
                                             memberName="NonStaticAppIdVar"/>
                            </parameters>
                        </constructedValue>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId1 is a constant value.-->
                                <classMember name="appId" classRef="ConstAndStaticAppIds" memberName="AppId1"/>

                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.App1Description is a constant value.-->
                                <classMember name="appDescription" classRef="ConstAndStaticAppIds"
                                             memberName="App1Description"/>
                            </parameters>
                        </constructedValue>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId2 is a static variable.-->
                                <classMember name="appId" classRef="ConstAndStaticAppIds" memberName="AppId2"/>

                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.App2Description is a static variable.-->
                                <classMember name="appDescription" classRef="ConstAndStaticAppIds"
                                             memberName="App2Description"/>
                            </parameters>
                        </constructedValue>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId3 is a static property.-->
                                <classMember name="appId" classRef="ConstAndStaticAppIds" memberName="AppId3"/>

                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.GetApp3Description is a static function-->
                                <classMember name="appDescription" classRef="ConstAndStaticAppIds"
                                             memberName="GetApp3Description"/>
                            </parameters>
                        </constructedValue>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.GetAppId4() is a static method.-->
                                <classMember name="appId" classRef="ConstAndStaticAppIds" memberName="GetAppId4"/>

                                <string name="appDescription" value="App 4"/>
                            </parameters>
                        </constructedValue>

                        <constructedValue typeRef="AppInfo">
                            <parameters>
                                <!--IoC.Configuration.Tests.ClassMember.Services.AppTypes.App1 is an enum value.-->
                                <classMember name="appId" classRef="AppTypes" memberName="App1"/>
                            </parameters>
                        </constructedValue>
                    </collection>
                </autoProperty>
            </autoService>

            <autoService interface="IoC.Configuration.Tests.ClassMember.Services.IAppIdToPriority">
                <autoMethod name="GetPriority" returnType="System.Int32">
                    <methodSignature>
                        <int32 paramName="appId"/>
                    </methodSignature>

                    <!--Property IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId is non-static, therefore
                      IoC.Configuration.Tests.ClassMember.Services.IAppIds will be resolved from dependency injection container,
                      and the value of property DefaultAppId in resolved object will be used in if condition-->
                    <if parameter1="_classMember:IAppIds.DefaultAppId">
                        <int32 value="14"/>
                    </if>

                    <!--Method IoC.Configuration.Tests.ClassMember.Services.IAppIds.GetAppId() is non-static, therefore
                      IoC.Configuration.Tests.ClassMember.Services.IAppIds will be resolved from dependency injection container,
                      and the value returned by method IAppIds.GetAppId()  will be used in if condition-->
                    <if parameter1="_classMember:IAppIds.GetAppId">
                        <int32 value="25"/>
                    </if>

                    <!--Variable IoC.Configuration.Tests.ClassMember.Services.AppIdVars.NonStaticAppIdVar is non-static/non-constant, therefore
                       IoC.Configuration.Tests.ClassMember.Services.AppIdVars will be resolved from dependency injection container,
                       and the value variable NonStaticAppIdVarin resolved object will be used in if condition.
                       NOTE, no need to add a self bound service for IoC.Configuration.Tests.ClassMember.Services.AppIdVars, since
                       IoC.Configuration will generated one. -->
                    <if parameter1="_classMember:IoC.Configuration.Tests.ClassMember.Services.AppIdVars.NonStaticAppIdVar">
                        <int32 value="23"/>
                    </if>

                    <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId1 is a constant value.-->
                    <if parameter1="_classMember:ConstAndStaticAppIds.AppId1">
                        <int32 value="4"/>
                    </if>

                    <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId2 is a static variable.-->
                    <if parameter1="_classMember:ConstAndStaticAppIds.AppId2">
                        <int32 value="7"/>
                    </if>

                    <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.AppId3 is a static property.-->
                    <if parameter1="_classMember:ConstAndStaticAppIds.AppId3">
                        <int32 value="8"/>
                    </if>

                    <!--IoC.Configuration.Tests.ClassMember.Services.ConstAndStaticAppIds.GetAppId4() is a static method.-->
                    <if parameter1="_classMember:ConstAndStaticAppIds.GetAppId4">
                        <int32 value="5"/>
                    </if>

                    <default>
                        <int32 value="0"/>
                    </default>
                </autoMethod>

                <autoMethod name="GetPriority" returnType="System.Int32">
                    <methodSignature>
                        <object paramName="appType" type="IoC.Configuration.Tests.ClassMember.Services.AppTypes"/>
                    </methodSignature>
                    <!--Example of using _classMember in If statement to reference enum value.-->
                    <if parameter1="_classMember:IoC.Configuration.Tests.ClassMember.Services.AppTypes.App1">
                        <int32 value="8"/>
                    </if>

                    <!--Example of using _classMember in If statement to reference enum value.-->
                    <if parameter1="_classMember:IoC.Configuration.Tests.ClassMember.Services.AppTypes.App2">
                        <int32 value="9"/>
                    </if>
                    <default>
                        <int32 value="1"/>
                    </default>
                </autoMethod>
            </autoService>
        </autoGeneratedServices>
    </dependencyInjection>

    <startupActions>

    </startupActions>

    <pluginsSetup>
        <pluginSetup plugin="Plugin1">
            <!--The type in pluginImplementation should be non-abstract class
                      that implements IoC.Configuration.IPlugin and which has a public constructor-->
            <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
            </pluginImplementation>

            <settings>
                <int32 name="Int32Setting1" value="10"/>
                <string name="StringSetting1" value="Some text"/>
            </settings>

            <dependencyInjection>
                <modules>
                </modules>

                <services>
                </services>

                <autoGeneratedServices>
                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>

        <pluginSetup plugin="Plugin2">
            <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2" assembly="pluginassm2">
                <parameters>
                    <boolean name="param1" value="true"/>
                    <double name="param2" value="25.3"/>
                    <string name="param3" value="String value"/>
                </parameters>
            </pluginImplementation>
            <settings>
            </settings>
            <dependencyInjection>
                <modules>
                </modules>
                <services>
                </services>
                <autoGeneratedServices>
                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>

        <pluginSetup plugin="Plugin3">
            <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3" assembly="pluginassm3">

            </pluginImplementation>
            <settings>
            </settings>
            <dependencyInjection>
                <modules>
                </modules>
                <services>
                </services>
                <autoGeneratedServices>
                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>
    </pluginsSetup>
</iocConfiguration>

IoCConfiguration_settingValue_ReferencingInConfiguration.xml

This configuration file can be downloaded downloaded from IoCConfiguration_settingValue_ReferencingInConfiguration.xml.

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
<?xml version="1.0" encoding="utf-8"?>

<!--
   The XML configuration file is validated against schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd,
   which can be found in folder IoC.Configuration.Content in output directory.
   The schema file can also be downloaded from
   http://oroptimizer.com/ioc.configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd or in source code
   project in Github.com.

   To use Visual Studio code completion based on schema contents, right click Properties on this file in Visual Studio, and in Schemas
   field pick the schema IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd.

   Before running the tests make sure to execute IoC.Configuration\Tests\IoC.Configuration.Tests\PostBuildCommands.bat to copy the dlls into
   folders specified in this configuration file.
   Also, modify the batch file to copy the Autofac and Ninject assemblies from Nuget packages folder on machine, where the test is run.
-->

<iocConfiguration
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">

  <!--The application should have write permissions to path specified in appDataDir.
    This is where dynamically generated DLLs are saved.-->
  <!--NOTE: path should be an absolute path, or should be converted to absolute path by some implementation of
     IoC.Configuration.AttributeValueTransformer.IAttributeValueTransformer. In this example the paths are converted by
     IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.-->
  <appDataDir
    path="TestFiles\AutogeneratedDlls\DynamicFiles_SettingValue" />

  <plugins pluginsDirPath="TestFiles\PluginDlls">

    <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->

    <!--A folder K:\...\IoC.Configuration\Tests\IoC.Configuration.Tests\bin\TestFiles\PluginDlls\Plugin1 should exist.  -->
    <plugin name="Plugin1" />
    <plugin name="Plugin2" enabled="true" />
    <plugin name="Plugin3" enabled="false" />
  </plugins>

  <additionalAssemblyProbingPaths>
    <probingPath
      path="TestFiles\ThirdPartyLibs" />
    <probingPath
      path="TestFiles\ContainerImplementations\Autofac" />
    <probingPath
      path="TestFiles\ContainerImplementations\Ninject" />
    <probingPath
      path="TestFiles\DynamicallyLoadedDlls" />
  </additionalAssemblyProbingPaths>

  <assemblies>
    <!--Assemblies should be in one of the following locations:
        1) Executable's folder
        2) In folder specified in additionalAssemblyProbingPaths element.
        3) In one of the plugin folders specified in plugins element (only for assemblies with plugin attribute) -->

    <!--
    Use "overrideDirectory" attribute, to make the assembly path explicit, rather then searching for
    an assembly in predefined folders, which also include probing paths specified in additionalAssemblyProbingPaths element.
    -->
    <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
    <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

    <assembly name="TestProjects.Modules" alias="modules" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly1"
              alias="dynamic1" />

    <assembly name="TestProjects.DynamicallyLoadedAssembly2"
              alias="dynamic2" />

    <assembly name="TestProjects.TestPluginAssembly1"
              alias="pluginassm1" plugin="Plugin1" />

    <assembly name="TestProjects.TestPluginAssembly2"
              alias="pluginassm2" plugin="Plugin2" />

    <assembly name="TestProjects.TestPluginAssembly3"
              alias="pluginassm3" plugin="Plugin3" />

    <assembly name="TestProjects.ModulesForPlugin1"
              alias="modules_plugin1" plugin="Plugin1" />

    <assembly name="TestProjects.SharedServices" alias="shared_services" />

    <assembly name="IoC.Configuration.Tests" alias="tests" />
  </assemblies>

  <typeDefinitions>

  </typeDefinitions>

  <parameterSerializers>
    <serializers></serializers>
  </parameterSerializers>

  <!--The value of type attribute should be a type that implements
    IoC.Configuration.DiContainer.IDiManager-->
  <diManagers activeDiManagerName="Autofac">
    <!-- TODO:-->
    <diManager name="Ninject" type="IoC.Configuration.Ninject.NinjectDiManager"
               assembly="ninject_ext">
      <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute has non-default constructor.
            -->
      <!--<parameters>
            </parameters>-->
    </diManager>

    <diManager name="Autofac" type="IoC.Configuration.Autofac.AutofacDiManager"
               assembly="autofac_ext">
    </diManager>
  </diManagers>

  <!--
    If settingsRequestor element is used, the type in type attribute should
    specify a type that implements IoC.Configuration.ISettingsRequestor.
    The implementation specifies a collection of required settings that should be present
    in settings element.
    Note, the type specified in type attribute is fully integrated into a dependency
    injection framework. In other words, constructor parameters will be injected using
    bindings specified in dependencyInjection element.
    -->

  <settings>
    <int32 name="defaultAppId" value="7"/>
    <string name="defaultAppDescr" value="Default App"/>
    <int32 name="app1" value="37"/>
    <string name="android" value="Android"/>
    <int32 name="defaultInt" value="-1"/>

    <!--This setting is redefined in plugin1 settings section to be of int type.
    Any services that reference a setting with name defaultColor, will be referencing the setting
    in plugin1
    -->
    <string name="defaultColor" value="Brown" />
  </settings>

  <dependencyInjection>
    <modules>
    </modules>
    <services>
      <service type="System.Int32">
        <valueImplementation scope="transient">
          <!--Demo of using a setting value in valueImplementation.-->
          <settingValue settingName="defaultInt"/>
        </valueImplementation>
      </service>

      <service type="System.Collections.Generic.IReadOnlyList[System.Int32]">
        <valueImplementation scope="singleton">
          <collection>
            <!--Example of using setting value in collection element-->
            <settingValue settingName="defaultInt"/>
            <settingValue settingName="app1"/>
            <int32 value="78"/>
          </collection>
        </valueImplementation>
      </service>

      <service type="IoC.Configuration.Tests.SettingValue.Services.IAppInfo" >
        <implementation type="IoC.Configuration.Tests.SettingValue.Services.AppInfo" scope="transient">
          <parameters>
            <!--Demo of using settingValue to inject value into an implementation constructor.-->
            <settingValue name="appId" settingName="defaultAppId"/>
          </parameters>
          <injectedProperties>
            <!--Demo of using settingValue to inject value into an implementation property.-->
            <settingValue name="AppDescription" settingName="defaultAppDescr"/>
          </injectedProperties>
        </implementation>
      </service>

      <service type="System.Collections.Generic.IReadOnlyList[IoC.Configuration.Tests.SettingValue.Services.IAppInfo]">
        <valueImplementation scope="singleton">
          <collection>
            <constructedValue type="IoC.Configuration.Tests.SettingValue.Services.AppInfo">
              <parameters>
                <!--Demo of using settingValue to inject a constructor parameter value in constructedValue element.-->
                <settingValue name="appId" settingName="defaultAppId"/>
              </parameters>
              <injectedProperties>
                <!--Demo of using settingValue to inject a property parameter value in constructedValue element.-->
                <settingValue name="AppDescription" settingName="defaultAppDescr"/>
              </injectedProperties>
            </constructedValue>
          </collection>
        </valueImplementation>
      </service>

    </services>

    <autoGeneratedServices>
      <!--The scope for autoService implementations is always singleton -->
      <autoService interface="IoC.Configuration.Tests.SettingValue.Services.IAppIds">

        <autoMethod name="GetDefaultAppId" returnType="System.Int32">
          <default>
            <settingValue settingName="defaultAppId"/>
          </default>
        </autoMethod>

        <autoMethod name="GetAppIds" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]">
          <methodSignature>
            <string paramName="platformType"/>
          </methodSignature>
          <!--Demo of using the value of setting named "android" in if condition in autoMethod-->
          <if parameter1="_settings:android">
            <collection>
              <!--Demo of setting value used as one of returned values in autoMethod if element.-->
              <settingValue settingName="defaultAppId"/>
              <settingValue settingName="app1"/>
              <int32 value="9"/>
            </collection>
          </if>

          <default>
            <collection>
              <!--Demo of setting value used as one of returned values in autoMethod default element.-->
              <settingValue settingName="defaultAppId"/>
              <int32 value="8"/>
            </collection>
          </default>
        </autoMethod>

        <autoProperty name="MainAppId" returnType="System.Int32">
          <!--Demo of setting value used as return value of autoProperty element.-->
          <settingValue settingName="defaultAppId"/>
        </autoProperty>

      </autoService>

    </autoGeneratedServices>
  </dependencyInjection>

  <startupActions>

  </startupActions>

  <pluginsSetup>
    <pluginSetup plugin="Plugin1">
      <!--The type in pluginImplementation should be non-abstract class
                that implements IoC.Configuration.IPlugin and which has a public constructor-->
      <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple">
      </pluginImplementation>

      <settings>

        <!--This setting with string type is also defined in non-plugin section.
          Since we re-defined the setting, any the references in plugin section to setting with name defaultColor,
          will be referencing the setting redefined here.
        -->
        <int32 name="defaultColor" value="4997399" />

        <int32 name="Int32Setting1" value="10"/>
        <string name="StringSetting1" value="Some text"/>
      </settings>

      <dependencyInjection>
        <modules>
        </modules>

        <services>
          <service type="TestPluginAssembly1.Interfaces.IDoor">
            <implementation type="TestPluginAssembly1.Implementations.Door" scope="transient">
              <parameters>
                <settingValue name="color" settingName="defaultColor"/>
                <int32 name="height" value="80"/>
              </parameters>
            </implementation>

          </service>
        </services>

        <autoGeneratedServices>

        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>

    <pluginSetup plugin="Plugin2">
      <pluginImplementation type="TestPluginAssembly2.Implementations.Plugin2" assembly="pluginassm2">
        <parameters>
          <boolean name="param1" value="true" />
          <double name="param2" value="25.3" />
          <string name="param3" value="String value" />
        </parameters>
      </pluginImplementation>
      <settings>
      </settings>
      <dependencyInjection>
        <modules>
        </modules>
        <services>
        </services>
        <autoGeneratedServices>
        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>

    <pluginSetup plugin="Plugin3">
      <pluginImplementation type="TestPluginAssembly3.Implementations.Plugin3" assembly="pluginassm3">

      </pluginImplementation>
      <settings>
      </settings>
      <dependencyInjection>
        <modules>
        </modules>
        <services>
        </services>
        <autoGeneratedServices>
        </autoGeneratedServices>
      </dependencyInjection>
    </pluginSetup>
  </pluginsSetup>
</iocConfiguration>

Type Binding In Modules

  • Type bindings can be specified either in IoC.Configuration module classes or in 3-rd party container modules, such as Autofac or Ninject modules.

Note

For details on how to specify type bindings in XML configuration file, see XML Configuration File.

  • To load the modules, use one of the following techniques
    • Specify the module types in iocConfiguration/dependencyInjection/modules/module elements in XML configuration file (if the configuration is loaded from XML configuration). See the following sections for more details on how to do this.
    • Load the modules directly, without loading any XML Configuration file. The module classes are specified as parameters in chained methods. To see how this is done, refer to Loading from Modules.

Type Bindings in IoC.Configuration Modules

Type Bindings in Implementation of IoC.Configuration.DiContainer.IDiModule

Type bindings can be specified either in implementation of Load() method of interface IoC.Configuration.DiContainer.IDiModule, or in overridden method AddServiceRegistrations in IoC.Configuration.DiContainer.ModuleAbstr.

Note

IoC.Configuration.DiContainer.ModuleAbstr is an implementation of interface IoC.Configuration.DiContainer.IDiModule.

Here is an example of specifying type bindings in overridden AddServiceRegistrations() method in a sub-class of IoC.Configuration.DiContainer.ModuleAbstr.

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        Bind<Class1>().ToSelf()
                      .SetResolutionScope(DiResolutionScope.Singleton);
        Bind<IInterface1>().To<Interface1_Impl1>()
                           .SetResolutionScope(DiResolutionScope.Singleton);
        Bind<Class2>().ToSelf()
                      .SetResolutionScope(DiResolutionScope.Transient);
        Bind<IInterface2>().To<Interface2_Impl1>()
                           .SetResolutionScope(DiResolutionScope.Transient);
        Bind<Class3>().ToSelf()
                      .SetResolutionScope(DiResolutionScope.ScopeLifetime);
        Bind<IInterface3>().To<Interface3_Impl1>()
                           .SetResolutionScope(DiResolutionScope.ScopeLifetime);
        Bind<Class4>().ToSelf()
                      .SetResolutionScope(DiResolutionScope.Singleton);
        Bind<Class4>().ToSelf()
                      .SetResolutionScope(DiResolutionScope.Transient);

        // The first binding should be with Singletone scope, and the second
        // should with Transient, so that we can test that the first binding was used.
        Bind<Class5>().OnlyIfNotRegistered()
                      .ToSelf().SetResolutionScope(DiResolutionScope.Singleton);
        Bind<Class5>().OnlyIfNotRegistered()
                      .ToSelf().SetResolutionScope(DiResolutionScope.Transient);

        // Only the first binding below will be registered.
        Bind<IInterface4>().OnlyIfNotRegistered().To<Interface4_Impl1>()
                           .SetResolutionScope(DiResolutionScope.Transient);
        Bind<IInterface4>().OnlyIfNotRegistered().To<Interface4_Impl2>()
                           .SetResolutionScope(DiResolutionScope.Singleton);

        // Both binding below will be registered
        Bind<IInterface5>().OnlyIfNotRegistered()
                           .To<Interface5_Impl1>()
                           .SetResolutionScope(DiResolutionScope.Transient);
        Bind<IInterface5>().To<Interface5_Impl2>()
                           .SetResolutionScope(DiResolutionScope.Singleton);

        // Test delegates and resolution using IDiContainer
        Bind<IInterface6>()
            .To(diContainer => new Interface6_Impl1(11, diContainer.Resolve<IInterface1>()));


        #region Test circular references

        Bind<ICircularReferenceTestInterface1>()
            .To<CircularReferenceTestInterface1_Impl>()
            .OnImplementationObjectActivated(
                (diContainer, instance) =>
                    // Note, type of instance is the implementation type
                    // CircularReferenceTestInterface1_Impl. So we can use Property1 setter.
                    // ICircularReferenceTestInterface1 has only getter for Property1.
                    instance.Property1 = diContainer.Resolve<ICircularReferenceTestInterface2>())
            .SetResolutionScope(DiResolutionScope.Singleton);

        Bind<ICircularReferenceTestInterface2>().To<CircularReferenceTestInterface2_Impl>()
                                                .SetResolutionScope(DiResolutionScope.Singleton);
        #endregion
    }
}

Note

The examples below demonstrate dependency injection concepts supported by IoC.Configuration package. Services are resolved using an instance of IoC.Configuration.DiContainer.IDiContainer. To see how to create an instance of IoC.Configuration.DiContainer.IDiContainer, refer to sections Loading from XML Configuration File and Loading from Modules. In examples below, it is assumed that an instance of IoC.Configuration.DiContainer.IDiContainer, diContainer, was already creating using one of the techniques described in these sections.

Types of Bindings

Binding to Self

This binding type can be used to specify that the type will be re-solved to an instance of the same type.

Here is an example of this type of binding in overridden method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations():

protected override void AddServiceRegistrations()
{
    Bind<Class1>().ToSelf()
          .SetResolutionScope(DiResolutionScope.Singleton);
}

Example of resolving the service Class1. Note, in example we use IoC.Configuration.DiContainer.IDiContainer to resolve Class1 for demonstration purposes, however normally we would just use a constructor injection.

private void SelfBoundServiceDemo(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    var implementation = diContainer.Resolve<Class1>();
    Assert.IsTrue(implementation.GetType() == typeof(Class1));
}
Binding to Type

This binding type can be used to specify that type will be bound to some other type, that is either the same type, implementation or sub-class of the type being re-solved.

Example of this type of binding in overridden method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations():

protected override void AddServiceRegistrations()
{
    //...
    Bind<IInterface2>().To<Interface2_Impl1>()
                       .SetResolutionScope(DiResolutionScope.Transient);
}

Example of resolving the service IInterface2.

private void BindToTypeDemo(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    var implementation = diContainer.Resolve<IInterface2>();

    Assert.IsTrue(implementation.GetType() == typeof(Interface2_Impl1));

    // Validate that the implementation is an instance of the resolved type.
    Assert.IsInstanceOfType(implementation, typeof(IInterface2));
}
Binding to a Delegate

Type is resolved to an object returned by a delegate.

Note

The delegate that is used to create an instance of resolved type accepts as a parameter an instance of IoC.Configuration.DiContainer.IDiContainer. This parameter can be used to resolve other types, when constructing the object to return.

Example of this type of binding in overridden method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations():

protected override void AddServiceRegistrations()
{
    //...
    Bind<IInterface6>().To(
    // The compiler will generate an error message if object of type IInterface6 is not assignable from an object of type Interface6_Impl1.
    diContainer => new Interface6_Impl1(11, diContainer.Resolve<IInterface1>()));
}

Example of resolving the service IInterface6.

private void BindToAValueReturnedByDelegate(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    //...
    var implementation = diContainer.Resolve<IInterface6>();
    Assert.IsInstanceOfType(implementation, typeof(IInterface6));
}
Specifying Resolution Scope

For more details on resolution scope, refer to section Resolution Scopes. Here we will just mention that all three resolution scopes are supporetd in IoC.Configuration modules.

Here are some examples on how to specify the resolution scope in overridden method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations().

protected override void AddServiceRegistrations()
{
    Bind<Class1>().ToSelf().SetResolutionScope(DiResolutionScope.Singleton);
    Bind<IInterface4>().To<Interface4_Impl1>().SetResolutionScope(DiResolutionScope.Transient);
    Bind<IInterface3>().To<Interface3_Impl1>().SetResolutionScope(DiResolutionScope.ScopeLifetime);
}

Property Injection and Circular References

The most common dependency injection type is a constructor injection, when dependency injection container creates objects and injects them into constructor of an object being resolved (this process is done recursively).

However, there are scenarios when two types reference each other. In this case constructor injection might fail. For example if type TypeA is specified as a constructor parameter in type TypeB and TypeB is specified as a constructor parameter in type TypeA, the dependency injection container will not be able to create an instance of TypeA, since it will need to create an instance of type TypeB, which requires creating an instance of type TypeA.

In such cases, property injection can be used to re-solve circular references. In this example type TypeB can be specified as a constructor parameter in type TypeA, and type TypeA can be a type of property TypeB.TypeAProperty, which will be initialized after the DI container created both types.

Here is an example of how property injection can be implemented in overridden AddServiceRegistrations() method in a sub-class of IoC.Configuration.DiContainer.ModuleAbstr:

In this example, the constructor of type CircularReferenceTestInterface2_Impl has a parameter of type ICircularReferenceTestInterface1, and the implementation of ICircularReferenceTestInterface1, CircularReferenceTestInterface1_Impl, has a setter property Property1 of type ICircularReferenceTestInterface2.

Note

The setter property used for property injection needs to be declared in implementation only.

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        Bind<ICircularReferenceTestInterface1>()
                    .To<CircularReferenceTestInterface1_Impl>()
                    .OnImplementationObjectActivated(
                        (diContainer, instance) =>
                         // Note, type of parameter 'instance' is the implementation type
                         // CircularReferenceTestInterface1_Impl. So we can use Property1 setter in
                         // CircularReferenceTestInterface1_Impl only and not in ICircularReferenceTestInterface1.
                         // ICircularReferenceTestInterface1 has only getter for Property1.
                         instance.Property1 = diContainer.Resolve<ICircularReferenceTestInterface2>())
                    .SetResolutionScope(DiResolutionScope.Singleton);

        Bind<ICircularReferenceTestInterface2>().To<CircularReferenceTestInterface2_Impl>()
                                                .SetResolutionScope(DiResolutionScope.Singleton);
    }
}

Type Bindings in 3-rd Party Container Modules

Third party module classes can be used to specify bindings.

The module class should be a sub-class or an implementation of a type returned by property Type ModuleType { get; } of IoC.Configuration.DiContainer.IDiManager object used to load the configuration.

To see of how IoC.Configuration.DiContainer.IDiManager type can be specified when loading the configuration, reference Loading from Modules (loading from modules) or Specifying DI Manager (loading from configuration file).

Currently two implementations of IoC.Configuration.DiContainer.IDiManager are available on Nuget:

The module types are passed as parameters, when loaded the configuration from modules (see Loading from Modules), or in iocConfiguration/dependencyInjection/modules/module elements in XML configuration file, if the configuration is loaded from XML file (see Modules).

Note

If the native module has a public method void OnDiContainerReady(IDiContainer diContainer), IoC.Configuration will call this method, when the dependency injection is loaded. The native module can use the IDiContainer object to resolve types in type bindings.

Here is an example of Autofac module:

public class AutofacModule1 : AutofacModule
{
    public IDiContainer DiContainer { get; private set; }

    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        builder.RegisterType<Interface1_Impl1>()
                .As<IInterface1>()
                .SingleInstance();
    }

    /// <summary>
    ///   The value of parameter <paramref name="diContainer" />
    ///   will be injected by <see cref="DiContainerBuilder" />.
    /// </summary>
    /// <param name="diContainer"></param>
    public void OnDiContainerReady(IDiContainer diContainer)
    {
        DiContainer = diContainer;
    }
}

Here is an example of Ninject module:

public class NinjectModule1 : NinjectModule
{
    public IDiContainer DiContainer { get; private set; }

    public override void Load()
    {
        Bind<IInterface1>().To<Interface1_Impl2>()
                           .InSingletonScope();
    }

    /// <summary>
    ///   The value of parameter <paramref name="diContainer" />
    ///   will be injected by <see cref="DiContainerBuilder" />.
    /// </summary>
    /// <param name="diContainer"></param>
    public void OnDiContainerReady(IDiContainer diContainer)
    {
        DiContainer = diContainer;
    }
}

XML Configuration File

An examples of XML configuration file can be found at IoCConfiguration_Overview.xml.

The sections below describe various aspects of configuration file.

Assemblies and Probing Paths

Elements appDataDir, plugins, additionalAssemblyProbingPaths, and assemblies define the assemblies and paths that the IoC.Configuration will search to locate the assembles.

Note

For more information about plugins refer to section Plugins.

Element: appDataDir

This element specifies the folder, where IoC.Configuration saves dynamically generated DLLs. The application should have write permissions to path specified in appDataDir.

Example of appDataDir in configuration file:

<appDataDir path="K:\...\IoC.Configuration.Tests\bin\TestFiles\DynamicFiles" />

Element: plugins

This element specifies the root folder, where plugin assemblies are, using the attribute pluginsDirPath, as well as might have plugin child elements to declare plugins (for more information about plugins refer to section Plugins).

The assemblies related to a plugin should be copied to a folder [plugins root folder]/[plugin name], where [plugins root folder] is the value of attribute pluginsDirPath of /iocConfiguration/plugins element, and [plugin name] is the value of name attribute in /iocConfiguration/plugins/plugin element.

For example the assemblies for plugin Plugin1 below should be in folder “K:...\TestDlls\PluginDlls\Plugin1”.

<plugins pluginsDirPath="K:\...\TestDlls\PluginDlls">

    <!--
    Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
    The plugin folders will be included in assembly resolution mechanism.
    -->

    <!--A folder K:\...\TestDlls\PluginDlls\Plugin1 should exist.  -->
    <plugin name="Plugin1" />
    <plugin name="Plugin2" />
    <plugin name="Plugin3" enabled="false" />
</plugins>

Here is an example of file structure with plugin folders.

_images/plugin-folders.jpg

Element: additionalAssemblyProbingPaths

This element specifies additional folders that IoC.Configuration will use for assembly resolution (this includes resolving assemblies defined in element assemblies as well as re-solving assemblies, on which assemblies in assemblies elements depend).

Here is an example of additionalAssemblyProbingPaths element:

<additionalAssemblyProbingPaths>
    <probingPath path="K:\...\TestDlls\ThirdPartyLibs" />
    <probingPath path="K:\...\TestDlls\ContainerImplementations\Autofac" />
    <probingPath path="K:\...\TestDlls\ContainerImplementations\Ninject" />
    <probingPath path="K:\...\TestDlls\DynamicallyLoadedDlls" />
    <probingPath path="K:\...\TestDlls\TestAssemblyResolution" />
</additionalAssemblyProbingPaths>

Element: assemblies and assembly

The elements assemblies and assembly specify all the assemblies that can be used when referencing types in XML configuration file. The assemblies in assemblies and their dependencies are resolved by looking up for assemblies in folders specified in elements plugins, additionalAssemblyProbingPaths, in addition to default folders (e.g., application startup folder, standard folder for .Net Core assemblies, etc).

Here is an example of assemblies element:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <assemblies>
        <assembly name="TestProjects.TestForceLoadAssembly"
                      alias="TestForceLoadAssembly"
                      overrideDirectory="K:\...\TestDlls\DynamicallyLoadedDlls" />

        <assembly name="OROptimizer.Shared" alias="oroptimizer_shared" />
        <assembly name="IoC.Configuration" alias="ioc_config" />
        <assembly name="IoC.Configuration.Autofac" alias="autofac_ext" />
        <assembly name="IoC.Configuration.Ninject" alias="ninject_ext" />

        <assembly name="TestProjects.Modules" alias="modules" />
        <assembly name="TestProjects.DynamicallyLoadedAssembly1" alias="dynamic1" />
        <assembly name="TestProjects.DynamicallyLoadedAssembly2" alias="dynamic2" />

        <assembly name="TestProjects.TestPluginAssembly1" alias="pluginassm1" plugin="Plugin1" />
        <assembly name="TestProjects.ModulesForPlugin1" alias="modules_plugin1" plugin="Plugin1" />
        <assembly name="TestProjects.TestPluginAssembly2" alias="pluginassm2" plugin="Plugin2" />
        <assembly name="TestProjects.TestPluginAssembly3" alias="pluginassm3" plugin="Plugin3" />

        <assembly name="TestProjects.SharedServices" alias="shared_services" />
        <assembly name="IoC.Configuration.Tests" alias="tests" />
    </assemblies>
Attributes in assembly element
  • name: Specifies the assembly name without the file extension. Example of this attribute value is IoC.Configuration.Autofac (see the XML above).

  • alias: A short unique alias to use, when referencing the assembly in other elements.

    Here is an example of element that references the assembly with alias dynamic1:

    <services>
        <service type="DynamicallyLoadedAssembly1.Interfaces.IInterface1" assembly="dynamic1">
            <implementation type="DynamicallyLoadedAssembly1.Implementations.Interface1_Impl1"
                            assembly="dynamic1" scope="singleton">
            </implementation>
        </service>
    </services>
    
  • plugin: An assembly that is in a plugin folder should include this attribute with value specifying the plugin name.

    Here is an example of assembly TestProjects.ModulesForPlugin1 with the value of attribute plugin being Plugin1.

    <assembly name="TestProjects.ModulesForPlugin1" alias="modules_plugin1" plugin="Plugin1" />
    

    Note

    There should exist some plugin element under element plugins, with the value of attribute name equal to Plugin1.

  • overrideDirectory: Specifies the directory, where the assembly should be loaded from. Normally this attribute should not be included in element, and the folders specified in elements plugins, additionalAssemblyProbingPaths, in addition to default folders will be searched to locate tbe assembly.

    Note

    Use this attribute in rare circumstances, to override the default behaviour.

    Here is an example of overrideDirectory attribute usage.

    <assembly name="TestProjects.TestForceLoadAssembly"
                          alias="TestForceLoadAssembly"
                          overrideDirectory="K:\...\TestDlls\DynamicallyLoadedDlls" />
    

Using Types in Configuration File

Many configuration elements reference C# types.

Either the full type name of the element should be specified using a type attribute (the attribute name might be different depending on element), or type alias should be specified, to reference a type declared in element under element /iocConfiguration/typeDefinitions/typeDefinitions (see below for more details).

Some examples are:

  • <service type=”DynamicallyLoadedAssembly1.Interfaces.IInterface1”>
  • <service type=”DynamicallyLoadedAssembly1.Interfaces.IInterface2 assembly=”shared_services”>
  • <service typeRef=”IInterface1”>
If the element uses the full type name, an optional attribute assembly can be used to specify the assembly, where the type is.

Note

Refer to Assemblies and Probing Paths for more details on assemblies in configuration file.

IoC.Configuration looks up the type in all the assemblies under element /iocConfiguration/assemblies.

Note

Refer to IoCConfiguration_GenericTypesAndTypeReUse.xml for more examples of using types in configuration file.

Generic Types in Configuration File

To reference generic types, list the comma separated generic type parameters within opening and closing square brackets (i.e., []) after the type name.

Some examples are:

<!--This type is similar to C# type
SharedServices.Implementations.Generic.Generic1_1<SharedServices.Implementations.Interface1_Impl1> -->
<implementation
    type="SharedServices.Implementations.Generic.Generic1_1[SharedServices.Implementations.Interface1_Impl1]"
    scope="singleton" />
<!--This type is similar to C# type
SharedServices.Interfaces.Generic.IGeneric2_1<SharedServices.Implementations.Generic.Generic3_1<System.Int32> -->
<service
    type="SharedServices.Interfaces.Generic.IGeneric2_1[SharedServices.Implementations.Generic.Generic3_1[System.Int32]]" >

Array Types in Configuration File

Array types can be specified by appending character # after the array item type name.

Example is:

<!--The type definition below is similar to C# type SharedServices.Interfaces.IInterface1[]-->
<service type="SharedServices.Interfaces.IInterface1#" >
    <!--Some implementation for service SharedServices.Interfaces.IInterface1[] goes here.-->
</service>

Re-Using Types

To avoid specifying the full type name in multiple elements in configuration file, we can define the type in /iocConfiguration/typeDefinitions/typeDefinition element, and reference the type using tye type alias in other elements.

Here is an example of declaring a type System.Collections.Generic.IEnumerable<SharedServices.Interfaces.IInterface1> with alias IEnumerableOf_IInterface1 in typeDefinition element:

<typeDefinitions>
    <typeDefinition
        alias="IEnumerableOf_IInterface1"
        type="System.Collections.Generic.IEnumerable[SharedServices.Interfaces.IInterface1]" />
</typeDefinitions>

Here is an example of referencing the type with alias IEnumerableOf_IInterface1 declared in typeDefinition element:

<service typeRef="IEnumerableOf_IInterface1">
    <!--Some implementation for service
    System.Collections.Generic.IEnumerable<SharedServices.Interfaces.IInterface1> goes here.-->
</service>

Parameter Serializers

The element parameterSerializers is used to de-serialize textual values used for type constructor parameters and property values, into objects of specific types.

Here is an example of parameterSerializers element.

 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
   <assemblies>
       <assembly name="OROptimizer.Shared" alias="oroptimizer_shared" />
       <assembly name="TestProjects.TestPluginAssembly1" alias="pluginassm1" plugin="Plugin1" />
       <assembly name="TestProjects.TestPluginAssembly2" alias="pluginassm1" plugin="Plugin2" />
       <!--Some more assemblies here...-->
   </assemblies>

   <parameterSerializers
               serializerAggregatorType="OROptimizer.Serializer.TypeBasedSimpleSerializerAggregator"
               assembly="oroptimizer_shared">
       <!--
       Use parameters element to specify constructor parameters,
       if the type specified in 'serializerAggregatorType' attribute
       has non-default constructor.
       -->
       <!--<parameters>
       </parameters>-->
       <serializers>
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerDouble"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerLong"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerInt"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerShort"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerByte"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerBoolean"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerDateTime"
                                assembly="oroptimizer_shared" />
           <parameterSerializer type="OROptimizer.Serializer.TypeBasedSimpleSerializerString"
                                assembly="oroptimizer_shared" />

           <parameterSerializer type="TestPluginAssembly1.Implementations.DoorSerializer"
                                assembly="pluginassm1" />
           <parameterSerializer type="TestPluginAssembly2.Implementations.WheelSerializer"
                                assembly="pluginassm2">
               <!--
               Use parameters element to specify constructor parameters,
               if the type specified in 'type' attribute has non-default constructor.
               -->
               <!--<parameters>
               </parameters>-->
           </parameterSerializer>
       </serializers>
   </parameterSerializers>
  • The value of attribute serializerAggregatorType in element parameterSerializers should be full name of a type that implements the interface OROptimizer.Serializer.ITypeBasedSimpleSerializerAggregator in assembly OROptimizer.Shared.dll (the assembly is available in Nuget package OROptimizer.Shared).

    The default implementation of this interface is class OROptimizer.Serializer.TypeBasedSimpleSerializerAggregator in assembly OROptimizer.Shared.dll.

  • Attribute assembly is an assembly alias, that contains the type specified in attribute serializerAggregatorType (the assembly should be declared in some element /iocConfiguration/assemblies/assembly).

  • Element parameters specifies values of constructor parameters for the type specified in attribute serializerAggregatorType (for details on constructor parameters reference Constructor Parameters).

  • Element serializers lists the registered serializers using parameterSerializer elements. Each parameterSerializer element registers a serializer for specific type (see the Element parameterSerializer section below).

Note

Some parameter serializers are provided by default, even if we do not list them under element parameterSerializers/serializers. Examples are serializers for some common types, such as parameter serializers for System.Int32, and System.Double, which are OROptimizer.Serializer.TypeBasedSimpleSerializerInt and OROptimizer.Serializer.TypeBasedSimpleSerializerDouble.

Element parameterSerializer

The element parameterSerializer registers a serializer for specific type. This element has two attributes, type and assembly, which are used to specify the full type name and the assembly for a serializer class that implements interface OROptimizer.Serializer.ITypeBasedSimpleSerializer.

Here is the definition of interface OROptimizer.Serializer.ITypeBasedSimpleSerializer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
   namespace OROptimizer.Serializer
   {
       /// <summary>
       ///     A simple serializer that serializes/de-serializes objects to and from strings.
       ///     The serialized string does not have any information about the type, so specific implementation de-serializes
       ///     specific type.
       ///     For example integer value 3 will be de-serialized from "3".
       /// </summary>
       public interface ITypeBasedSimpleSerializer
       {
           Type SerializedType { get; }
           bool TryDeserialize(string valueToDeserialize, out object deserializedValue);
           bool TrySerialize(object valueToSerialize, out string serializedValue);
       }
   }

Note

The property OROptimizer.Serializer.ITypeBasedSimpleSerializer.SerializedType is used to pick a deserializer type from the serializers registered in element parameterSerializers.

Example 1

Note

Refer to Constructor Parameters for more details on parameters element to specify constructor parameter values in configuration file.

The selfBoundService element below is a definition of self-bound service for type DynamicallyLoadedAssembly1.Implementations.SelfBoundService1 from configuration file.

<selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService1"
                              assembly="dynamic1"
                              scope="singleton">
    <parameters>
        <int32 name="param1" value="14" />
        <double name="param2" value="15.3" />
        <injectedObject name="param3" type="DynamicallyLoadedAssembly1.Interfaces.IInterface1"
                        assembly="dynamic1" />
    </parameters>
</selfBoundService>

The type DynamicallyLoadedAssembly1.Implementations.SelfBoundService1 has a constructor with three parameters of types System.Int32, System.Double, and DynamicallyLoadedAssembly1.Interfaces.IInterface1.

  • Since there is a parameterSerializer element (see example of parameterSerializers element above) for type System.Int32 (i.e., OROptimizer.Serializer.TypeBasedSimpleSerializerInt), which de-serializes textual values into System.Int32 values, IoC.Configuration will use OROptimizer.Serializer.TypeBasedSimpleSerializerInt to de-serialze the textual value “14” into a System.Int32 value for the constructor parameter param1.
  • Since there is a parameterSerializer element (see example of parameterSerializers element above) for type System.Double (i.e., OROptimizer.Serializer.TypeBasedSimpleSerializerDouble), which de-serializes textual values into System.Double values, IoC.Configuration will use OROptimizer.Serializer.TypeBasedSimpleSerializerDouble to de-serialze the textual value “15.3” into an System.Double value for the constructor parameter param2.
  • The constructor parameter param3 will be injected into constructor of DynamicallyLoadedAssembly1.Implementations.SelfBoundService1, using dependency injection mechanism, since injectedObject element is used for this parameter.
Example 2

Note

Refer to Constructor Parameters for more details on parameters element to specify constructor parameter values in configuration file.

The service element below defines type bindings for interface TestPluginAssembly1.Interfaces.IRoom.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    <service type="TestPluginAssembly1.Interfaces.IRoom" assembly="pluginassm1">
        <implementation type="TestPluginAssembly1.Implementations.Room"
                        assembly="pluginassm1"
                        scope="transient">
            <parameters>
                <object name="door1" type="TestPluginAssembly1.Interfaces.IDoor"
                        assembly="pluginassm1"
                        value="5,185.1" />
                <injectedObject name="door2" type="TestPluginAssembly1.Interfaces.IDoor"
                                assembly="pluginassm1" />
            </parameters>
            <injectedProperties>
                <object name="Door2" type="TestPluginAssembly1.Interfaces.IDoor"
                        assembly="pluginassm1"
                        value="7,187.3" />
            </injectedProperties>
        </implementation>
    </service>

The constructor of type TestPluginAssembly1.Implementations.Room in element implementation has two constructor parameters named door1 and door2, both of type TestPluginAssembly1.Interfaces.IDoor.

  • Since there is a parameterSerializer element (see example of parameterSerializers element above) for type TestPluginAssembly1.Implementations.DoorSerializer, which de-serializes textual values into TestPluginAssembly1.Interfaces.IDoor values, IoC.Configuration will use TestPluginAssembly1.Implementations.DoorSerializer to de-serialze the textual value “5,185.1” into a TestPluginAssembly1.Interfaces.IDoor value to use for constructor parameter door1.
  • The constructor parameter door2 will be injected into constructor of TestPluginAssembly1.Implementations.Room, using dependency injection mechanism, since injectedObject element is used for this parameter.
  • Property TestPluginAssembly1.Implementations.Room.Door2 has a setter, and is of type TestPluginAssembly1.Interfaces.IDoor as well, therefore IoC.Configuration will use TestPluginAssembly1.Implementations.DoorSerializer as well, to de-serialze the textual value “7,187.3” into a TestPluginAssembly1.Interfaces.IDoor value and to assign this value to a property TestPluginAssembly1.Implementations.Room.Door2 in bound object of type TestPluginAssembly1.Implementations.Room.

Constructor Parameters

Element parameters is used to specify constructor parameter values for a type specified in XML configuration file.

Element parameters has one child element per constructor parameter.

Child elements are byte, int16, int32, int64, double, boolean, datetime, string, object, and injectedObject.

  • Elements, byte, int16, int32, int64, double, boolean, datetime, string, are straightforward, and are used to specify constructor parameters of the same type (byte, System.Int32, string, etc).

  • Element object is used to provide a constructor parameter value of arbitrary type using attributes type and assembly, as well as attribute value. The value in attribute value will be de-serialized into an instance of type specified in attributes type and assembly, using a serializer registered in element iocConfiguration/parameterSerializers for the type.

    Note

    Refer to Parameter Serializers for more details on parameter serializers.

  • Element injectedObject is used to specify a constructor parameter that should be injected using the dependency injection mechanism.

    Note

    Child elements injectedObject are valid based on context, where parameters element is used. For example this element can be used when specifying service bindings, as shown in examples below, however it cannot be used in settings element.

Example 1

In example below, service of type DynamicallyLoadedAssembly1.Implementations.SelfBoundService1 will be bound to an instance of the same type, which will be created using a constructor with three parameters of types int, double, and DynamicallyLoadedAssembly1.Interfaces.IInterface1.

  • Parameter param1 of type System.Int32 will be initialized from textual value 14 using the parameter serializer OROptimizer.Serializer.TypeBasedSimpleSerializerInt in assembly OROptimizer.Shared.
  • Parameter param2 of type System.Double will be initialized from textual value 15.3 using the parameter serializer OROptimizer.Serializer.TypeBasedSimpleSerializerDouble in assembly OROptimizer.Shared.
  • Parameter param3 of type DynamicallyLoadedAssembly1.Interfaces.IInterface1 will be injected into constructor of DynamicallyLoadedAssembly1.Implementations.SelfBoundService1.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService1"
                                  assembly="dynamic1"
                                  scope="singleton">
        <parameters>
            <int32 name="param1" value="14" />
            <double name="param2" value="15.3" />
            <injectedObject name="param3" type="DynamicallyLoadedAssembly1.Interfaces.IInterface1"
                            assembly="dynamic1" />
        </parameters>
    </selfBoundService>

Example 2

In example below, service of type TestPluginAssembly1.Interfaces.IRoom will be bound to an instance of type TestPluginAssembly1.Implementations.Room, which will be created using a constructor that has two parameters, door1 and door2, of type TestPluginAssembly1.Interfaces.IDoor.

  • The first parameter door1 will be de-serialized from text 5,185.1, using a serializer TestPluginAssembly1.Implementations.DoorSerializer, found under element iocConfiguration/parameterSerializers for type TestPluginAssembly1.Interfaces.IDoor.

    Note

    Refer to Parameter Serializers for more details on parameter serializers.

  • The second parameter door2 will be injected into constructor of TestPluginAssembly1.Implementations.Room.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    <service type="TestPluginAssembly1.Interfaces.IRoom" assembly="pluginassm1">
        <implementation type="TestPluginAssembly1.Implementations.Room"
                        assembly="pluginassm1"
                        scope="transient">
            <parameters>
                <object name="door1" type="TestPluginAssembly1.Interfaces.IDoor"
                        assembly="pluginassm1"
                        value="5,185.1" />
                <injectedObject name="door2" type="TestPluginAssembly1.Interfaces.IDoor"
                                assembly="pluginassm1" />
            </parameters>
        </implementation>
    </service>

Example 3

This example is similar to Example 2 above, however parameters element is missing under the implementation type TestPluginAssembly1.Implementations.Room. Since no parameters element is provided, an instance of type TestPluginAssembly1.Implementations.Room will be injected using dependency injection mechanism, rather than using a specific constructor.

Note

If a parameters element is provided without any child parameters, an instance of type will be created using the default parameter-less constructor. Therefore the type is expected to have a default constructor. To use dependency injection mechanism to construct an instance of type, one should omit the parameters element, instead of providing an empty parameters element.

1
2
3
4
5
6
    <service type="TestPluginAssembly1.Interfaces.IRoom" assembly="pluginassm1">
        <implementation type="TestPluginAssembly1.Implementations.Room"
                        assembly="pluginassm1"
                        scope="transient">
        </implementation>
    </service>

Settings

The configuration file has two elements related to settings: /iocConfiguration/settingsRequestor and /iocConfiguration/settings

Note

See Plugins for details on settings in plugins.

Here is an example of settings in XML configuration file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    <iocConfiguration>

        <settingsRequestor type="SharedServices.FakeSettingsRequestor"
                            assembly="shared_services">
        </settingsRequestor>

        <settings>
            <int32 name="SynchronizerFrequencyInMilliseconds" value="5000" />
            <double name="MaxCharge" value="155.7" />
            <string name="DisplayValue" value="Some display value" />
        </settings>
    </iocConfiguration>
  • Element settings lists all the settings using elements byte, int16, int32, int64, double, boolean, datetime, string, object. The values of settings are de-serialized using serializers provided in element parameterSerializers (reference section Parameter Serializers).

  • Element settingsRequestor is optional and if present, is used to force the user to include settings using the type specified in attributes type and assembly. The specified type should implement an interface IoC.Configuration.ISettingsRequestor, which specifies a collection of required settings that should be present in settings element.

    Note

    The type specified in type attribute in settingsRequestor element is fully integrated into a dependency injection framework. In other words, constructor parameters will be injected using bindings specified in dependencyInjection element.

Interface IoC.Configuration.ISettingsRequestor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    namespace IoC.Configuration
    {
        public interface ISettingsRequestor
        {
            /// <summary>
            /// Gets the collection of settings, that should be
            /// present in configuration file.
            /// </summary>
            [NotNull, ItemNotNull]
            IEnumerable<SettingInfo> RequiredSettings { get; }
        }
    }

Accessing Setting Values in Code

To access the setting values in code, inject the type IoC.Configuration.ISettings as a constructor parameter, and use the methods bool GetSettingValue<T>(string name, T defaultValue, out T value) or T GetSettingValueOrThrow<T>(string name) in IoC.Configuration.ISettings.

Here is an example:

 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
    public class TestInjectedSettings
    {
        public TestInjectedSettings(ISettings settings)
        {
            Assert.IsTrue(settings.GetSettingValue<double>("MaxCharge", 5.3,
                                            out var maxChargeSettingValue));
            Assert.AreEqual(155.7, maxChargeSettingValue);

            Assert.IsFalse(settings.GetSettingValue<int>("MaxCharge", 5,
                                            out var settingValueNotFound_InvalidType));
            Assert.AreEqual(5, settingValueNotFound_InvalidType);

            Assert.IsFalse(settings.GetSettingValue<int>("MaxChargeInvalid", 7,
                                            out var nonExistentSettingValue));
            Assert.AreEqual(7, nonExistentSettingValue);

            try
            {
                // This call will throw an exception, since there is no setting of double
                // type with name "MaxChargeInvalid".
                settings.GetSettingValueOrThrow<double>("MaxChargeInvalid");
                Assert.Fail("An exception should have been thrown.");
            }
            catch
            {
            }
        }
    }

Note

Binding for a type TestInjectedSettings should be registered either in module class or in XML configuration file. Below is an example of registering binding for TestInjectedSettings in an IoC.Configuration module.

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        this.Bind<TestInjectedSettings>().ToSelf();
    }
}

Specifying DI Manager

  • The XML configuration file has a required element diManagers, for specifying types that implement interface IoC.Configuration.DiContainer.IDiManager. The IoC.Configuration.DiContainer.IDiManager implementations are specified in child diManager elements.

  • Also, diManagers element has an attribute activeDiManagerName, that specifies which IoC.Configuration.DiContainer.IDiManager will be used to handle IoC type bindings and type resolutions, as well as some other dependency injection related behaviour (such as valid module types, etc).

    Note

    Currently two implementations of IoC.Configuration.DiContainer.IDiManager are available: IoC.Configuration.Ninject.NinjectDiManager and IoC.Configuration.Autofac.AutofacDiManager in Nuget packages IoC.Configuration.Ninject and IoC.Configuration.Autofac

  • The selected IoC.Configuration.DiContainer.IDiManager implementation (e.g., IoC.Configuration.Ninject.NinjectDiManager, IoC.Configuration.Autofac.AutofacDiManager) handles type bindings that are specified in IoC.Configuration modules, as well as type resolutions.

Example of this element is shown below. To switch between Ninject and Aurofac containers, one needs to set the value of activeDiManagerName to either Ninject or Aurofac.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    <diManagers activeDiManagerName="Autofac">
        <diManager name="Ninject"
                type="IoC.Configuration.Ninject.NinjectDiManager"
                assembly="ninject_ext">
            <!--
            Use parameters element to specify constructor parameters,
            if the type specified in 'type' attribute
            has non-default constructor.-->
            <!--<parameters>
            </parameters>-->
        </diManager>
        <diManager name="Autofac"
                 type="IoC.Configuration.Autofac.AutofacDiManager"
                 assembly="autofac_ext">
        </diManager>
    </diManagers>

Dependency Injection

The XML configuration file has dependencyInjection element which is used to specify modules (both IoC.Configuration modules, as well as native, such as Autofac or Ninject modules), service bindings, autogenerated service bindings, etc.

Modules

The iocConfiguration/dependencyInjection/modules element lists the modules (both IoC.Configuration modules, as well as native modules, such as Autofac or Ninject modules), that should be loaded into the IoC container. See Type Binding In Modules for more details on modules.

Here is an example of modules element in configuration file:

 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
    <iocConfiguration>
    <!--...-->
        <dependencyInjection>
            <modules>
                <!--Type Modules.Autofac.AutofacModule1 is an Autofac module and is a
                                        subclass of Autofac.AutofacModule-->
                <module type="Modules.Autofac.AutofacModule1" assembly="modules">
                    <parameters>
                        <int32 name="param1" value="1" />
                    </parameters>
                </module>

                <!--Type Modules.IoC.DiModule1 is an IoC.Configuration module and is a
                    subclass of IoC.Configuration.DiContainer.ModuleAbstr-->
                <module type="Modules.IoC.DiModule1" assembly="modules">
                    <parameters>
                        <int32 name="param1" value="2" />
                    </parameters>
                </module>

                <!--Type Modules.Ninject.NinjectModule1 is a Ninject module and is a
                                         subclass of Ninject.Modules.NinjectModule-->
                <module type="Modules.Ninject.NinjectModule1" assembly="modules">
                    <parameters>
                        <int32 name="param1" value="3" />
                    </parameters>
                </module>
            </modules>

            <!--...-->
        </dependencyInjection>

        <!--...-->
    <iocConfiguration>
  • Each child module element in modules element specifies a module type that should be either IoC.Configuration module (i.e., should either implement interface IoC.Configuration.DiContainer.IDiModule or be a subclass of IoC.Configuration.DiContainer.ModuleAbstr class), or should be a native module (e.g., Autofac or Ninject module).
  • If the type specified by module is a native module (e.g., Autofac or Ninject module), then the type of the module should be assignable from one of the types specified by property IoC.Configuration.DiContainer.IDiManager.ModuleType in IDiManager objects listed in iocConfiguration/diManagers/diManager elements (see Specifying DI Manager for more details on specifying IoC.Configuration.DiContainer.IDiManager implementations).
  • IoC.Configuration modules (i.e., modules that either implement interface IoC.Configuration.DiContainer.IDiModule or are subclasses of IoC.Configuration.DiContainer.ModuleAbstr class), and native modules (i.e., Autofac or Ninject modules), can be listed in any order in element iocConfiguration/dependencyInjection/modules.
  • Constructor parameter values can be specified using parameters element, if the module does not have a default constructor (see Constructor Parameters for more details about constructor parameters).

Service Bindings

  • The element iocConfiguration/dependencyInjection/services lists service bindings that will be loaded into IoC container.
  • The element iocConfiguration/dependencyInjection/services has two types of child elements, service and selfBoundService.
Element service

Element service is used to bind a type specified in attributes type and assembly to one ore more types specified in implementation child elements.

Single Implementation

An example of service element that binds type SharedServices.Interfaces.IInterface4 in assembly with alias shared_services to a type SharedServices.Implementations.Interface4_Impl1 is shown below.

<!--...-->
<services>
    <!--...-->
    <service type="SharedServices.Interfaces.IInterface4" assembly="shared_services">
        <implementation type="SharedServices.Implementations.Interface4_Impl1"
                        assembly="shared_services"
                        scope="singleton">
        </implementation>
    </service>
    <!--...-->
</services>

An instance of type SharedServices.Implementations.Interface4_Impl1 will be injected as a constructor parameter or into properties by dependency injection, when interface SharedServices.Interfaces.IInterface4 is requested.

Here is an example of injecting SharedServices.Implementations.Interface4_Impl1 as a constructor parameter interface4.

public class TestConstructorInjection
{
    // An instance of type SharedServices.Implementations.Interface4_Impl1 will
    // be injected for constructor parameter interface4.
    public TestConstructorInjection(SharedServices.Interfaces.IInterface4 interface4)
    {
    }
}
Multiple Implementations

If multiple implementation elements are specified under service element, the type specified in element service will be bound to multiple types. In such a cases we should use System.Collections.Generic.IEnumerable<TService>.

An example of service element that binds a type SharedServices.Interfaces.IInterface8 in assembly with alias shared_services to two types, SharedServices.Implementations.Interface8_Impl1 and SharedServices.Implementations.Interface8_Impl2 is shown below.

<!--...-->
<services>
    <service type="SharedServices.Interfaces.IInterface8"
             assembly="shared_services">
        <implementation type="SharedServices.Implementations.Interface8_Impl1"
                        assembly="shared_services"
                        scope="singleton">
        </implementation>

        <implementation type="SharedServices.Implementations.Interface8_Impl2"
                        assembly="shared_services"
                        scope="transient">
        </implementation>
    </service>
    <!--...-->
</services>

Here is an example of injecting instances of types SharedServices.Implementations.Interface8_Impl1 and SharedServices.Implementations.Interface8_Impl2 for parameter interface8Resolutions of type System.Collections.Generic.IEnumerable<SharedServices.Interfaces.IInterface8>.

In this example, the injected collection interface8Resolutions will have two items. The first item will be of type SharedServices.Implementations.Interface8_Impl1 and the second item will be of type SharedServices.Implementations.Interface8_Impl2.

public class TestConstructorInjectionForMultipleBindings
{
    public TestConstructorInjection(
            IEnumerable<SharedServices.Interfaces.IInterface8> interface8Resolutions)
    {
    }
}
Binding Scope

Attribute scope in element implementation under element service is used to specify binding resolution scope for resolved types (see Resolution Scopes for more details). The value of this attribute can be one of the following: singleton, transient, and scopeLifetime.

Element selfBoundService

Element selfBoundService is used to bind a type specified in attributes type and assembly to itself.

An example of selfBoundService element to bind type DynamicallyLoadedAssembly1.Implementations.SelfBoundService3 in assembly with alias dynamic1 to itself is shown below.

<!--...-->
<services>
    <!--...-->
    <selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService3"
                      assembly="dynamic1"
                      scope="scopeLifetime">
    </selfBoundService>
    <!--...-->
</services>

An instance of type DynamicallyLoadedAssembly1.Implementations.SelfBoundService3 will be injected as a constructor parameter or into properties by the dependency injection, when type DynamicallyLoadedAssembly1.Implementations.SelfBoundService3 is requested.

Here is an example of injecting DynamicallyLoadedAssembly1.Implementations.SelfBoundService3 as a constructor parameter selfBoundService3.

public class TestConstructorInjection
{
    public TestConstructorInjection(
            DynamicallyLoadedAssembly1.Implementations.SelfBoundService3 selfBoundService3)
    {
    }
}
Binding Scope

Attribute scope in element implementation under element service is used to specify binding resolution scope for resolved types (see Resolution Scopes for more details). The value of this attribute can be one of the following: singleton, transient, and scopeLifetime.

Element proxyService

Element iocConfiguration/dependencyInjection/services/proxyService (or iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/services/proxyService for plugins) can be used to resolve multiple services to the same implementation.

Lets say we have an interface IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension which extends interfaces IoC.Configuration.Tests.ProxyService.Services.IAppManager and IoC.Configuration.Tests.ProxyService.Services.IAppManager2, as shown below.

namespace IoC.Configuration.Tests.ProxyService.Services
{
    public interface IAppManager_Extension : IAppManager, IAppManager2
    {
        IAppData DefaultApp { get; }
    }
}

We want to make sure that services IoC.Configuration.Tests.ProxyService.Services.IAppManager and IoC.Configuration.Tests.ProxyService.Services.IAppManager2 are resolved to the same type, to which service IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension is resolved.

This can be done using proxyService elements as shown below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<services>

      <!--IoC.Configuration.Tests.ProxyService.Services.IAppManager
        will be resolved by resolving
        IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension.-->
      <proxyService
        type="IoC.Configuration.Tests.ProxyService.Services.IAppManager" >
        <serviceToProxy
            type="IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension" />
      </proxyService>

      <!--IoC.Configuration.Tests.ProxyService.Services.IAppManager2 will
          also be resolved to
          IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension.-->
      <proxyService type="IoC.Configuration.Tests.ProxyService.Services.IAppManager2" >
        <serviceToProxy
            type="IoC.Configuration.Tests.ProxyService.Services.IAppManager_Extension"/>
      </proxyService>

      <!--Some more services here.-->
</services>

Another use case for proxy services is when have module(s) that scan assemblies and self-binds non-abstract classes. In this cases we can use “proxyService” element if we want the interface specified in “proxyService” element to resolve to exactly the same value to which the self bound class is bound.

For example lets say we have a module that has a binding like

1
Bind<DatabaseMetadata>().ToSelf().SetResolutionScope(DiResolutionScope.Singleton);

If we bind IDatabaseMetadata to DatabaseMetadata in configuration like the following

1
2
3
4
5
<services>
    <service type="IDatabaseMetadata">
      <implementation type="DatabaseMetadata" scope="singleton" />
    </service>
<services>

In this case the following two resolutions will result in two different instances

1
2
3
IDiContainer diContainer; // IDiContainer will be initialized from IoC.Configuration
var instance1 = diContainer.Resolve<DatabaseMetadata>();
var instance2 = diContainer.Resolve<IDatabaseMetadata>();

The reason is that the underlying native DI containers (Ninject, Autofac, etc), might disregard that there is a self bound registration for DatabaseMetadata, when registering the binding for IDatabaseMetadata. In other words, IDatabaseMetadata might be bound by using reflection to create DatabaseMetadata object, and not be bound by resolving DatabaseMetadata.

To resolve this issue, we might use ‘proxyService’ element in configuration file to bind IDatabaseMetadata interface to the same instance to which class DatabaseMetadata is bound:

1
2
3
4
5
<services>
    <proxyService type="IDatabaseMetadata">
        <serviceToProxy type="DatabaseMetadata"/>
    </proxyService>
<services>

The same result can be achieved using binding in module as follows:

1
2
3
4
5
6
7
public class DiModule1 : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        Bind<IDatabaseMetadata>().To(x => x.Resolve<MetadataDatabaseMetadata>());
    }
}
Element valueImplementation

Element valueImplementation can be used under element iocConfiguration/dependencyInjection/services/service (or iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/services/service for plugin section), to bind the service to a value specified using a value initialization element (e.g., such elements as int32, int64 collection, settingValue, classMember, object, constructedValue).

Note

Refer to Value Initialization Elements for details on value initialization elements.

Note

Refer to IoCConfiguration_valueImplementation.xml for more examples on valueImplementation element.

Example 1: Using valueImplementation to bind System.Int32 to a setting value
1
2
3
4
5
<service type="System.Int32">
    <valueImplementation scope="singleton">
      <settingValue settingName="defaultAppId"/>
    </valueImplementation>
</service>
Example 2: Using valueImplementation to bind System.Double to 3.5
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<service type="System.Double">
    <valueImplementation scope="singleton">
        <!--
            The out of the box serializer for System.Double is
            OROptimizer.Serializer.TypeBasedSimpleSerializerDouble
            which is available in Nuget package OROptimizer.Shared.
        -->
        <object type="System.Double" value="3.5"/>
    </valueImplementation>
</service>
Example 3: Using valueImplementation to bind service to class member
1
2
3
4
5
6
7
<service type="SharedServices.Interfaces.IDbConnection">
    <valueImplementation scope="transient">
        <classMember
            class="IoC.Configuration.Tests.ValueImplementation.Services.IDbConnectionProvider"
            memberName="GetDbConnection"/>
    </valueImplementation>
</service>
Example 4: Using valueImplementation to bind service to collection
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<service
    type="System.Collections.Generic.IReadOnlyList[IoC.Configuration.Tests.ValueImplementation.Services.IAppInfo]">

    <valueImplementation scope="singleton" >
        <collection>
            <constructedValue typeRef="AppInfo">
              <parameters>
                <int32 name="paramId" value="1"/>
              </parameters>
            </constructedValue>

            <constructedValue typeRef="AppInfo">
              <parameters>
                <int32 name="paramId" value="2"/>
              </parameters>
            </constructedValue>
        </collection>
    </valueImplementation>
</service>
Implementation Type Constructor Parameters

Normally we do not need to specify constructor parameters when specifying type bindings, since the constuctor parameters will be injected. However, in some cases we want to explicitly specify constructor parameter values in bound type.

Here are some of the cases when explicitly specifying constructor parameters might be useful:

  • The bound type has multiple constructors, and we want to explicitly specify which constructor should be used.
  • The bound type constructor has some parameters, which cannot be injected since no bindings are provided for the types of these parameters.
  • We want to explicitly specify the constructor parameter values (say for primitive types, such as System.Int32, System.Double, etc), instead of relying on IoC container to inject these constructor parameter values.

Note

Normally, if there are multiple constructors, the IoC container will pick the constructor with largest number of parameters. This pattern is true for Autofac and Ninject, however might be different for other implementations.

Element parameters
  • Use parameters in element implementation or selfBoundService to provide constructor parameter values.
  • If parameters is used without any values (see Example 1 below), than the default constructor will be used to construct an instance of bound type, even if there are other constructors. In this case an exception will be thrown if the bound type does not have a default constructor. To let the IoC pick the constructor, do not use any parameters element in implementation and selfBoundService elements.
  • IoC.Configuration will use parameter serializers specified in element iocConfiguration/parameterSerializers to de-serialize the values of parameters specified in child elements of element parameters (see Parameter Serializers).
  • When the IoC.Configuration uses reflection to find the constructor using parameter types specified under parameters element. If no constructor is found, and exception will be thrown.
Example 1

In the example below, type DynamicallyLoadedAssembly1.Implementations.SelfBoundService1 is bound to itself.

  • When injecting an instance of DynamicallyLoadedAssembly1.Implementations.SelfBoundService1, the object will be constructed using the constructor with three parameters of types System.Int32, System.Double, and DynamicallyLoadedAssembly1.Interfaces.IInterface1.
  • The first and second parameter values will be de-serialized from textual values 14 and 15.3.
  • The third parameter value will be injected by IoC.Configuration, since injectedObject is used for this parameter. A binding for DynamicallyLoadedAssembly1.Interfaces.IInterface1 should be specified in XML configuration file or in modules being loaded.

Note

IoC.Configuration will automatically register a self bound service for a type specified in element injectedObject, if the type is not an abstract type or an interface, and if it is not already registered in configuration file. Therefore, if in example below we replace DynamicallyLoadedAssembly1.Interfaces.IInterface1 with DynamicallyLoadedAssembly1.Interfaces.IInterface1_Implementation (i.e., non-abstract implementation of DynamicallyLoadedAssembly1.Interfaces.IInterface1), there will be no need to provide a binding for DynamicallyLoadedAssembly1.Interfaces.IInterface1_Implementation.

Note

Using injectedObject, we can specify a type other than a type registered for interface DynamicallyLoadedAssembly1.Interfaces.IInterface1 (i.e., the type of parameter param3). In other words, no matter what bindings are specified for interface DynamicallyLoadedAssembly1.Interfaces.IInterface1, the object injected for parameter param3 will be of type specified in injectedObject element.

<selfBoundService type="DynamicallyLoadedAssembly1.Implementations.SelfBoundService1"
                  assembly="dynamic1"
                  scope="singleton">
    <parameters>
        <int32 name="param1" value="14" />
        <double name="param2" value="15.3" />
        <injectedObject name="param3"
                        type="DynamicallyLoadedAssembly1.Interfaces.IInterface1"
                        assembly="dynamic1" />
    </parameters>
</selfBoundService>
Example 2

In the example below, interface SharedServices.Interfaces.IRoom is bound to class SharedServices.Implementations.Room.

When injecting an instance of SharedServices.Interfaces.IRoom, an object of type SharedServices.Implementations.Room will be constructed using a constructor with two parameter, both of type SharedServices.Interfaces.IDoor.

  • The first parameter value will be de-seriazed from string “5,185.1” provided in attribute value in element object. A parameter serializer for type SharedServices.Interfaces.IDoor should be specified in element iocConfiguration/parameterSerializers/serializers (see Parameter Serializers for more details).
  • The second parameter value will be injected by IoC.Configuration, since injectedObject is used for parameter value.

Note

IoC.Configuration will automatically register a self bound service for a type specified in element injectedObject, if the type is not an abstract type or an interface, and if it is not already registered in configuration file. Therefore, no need to register a binding for type SharedServices.Interfaces.OakDoor used in injectedObject for parameter door2, since this type is non-abstract and non-interface.

Note

Using injectedObject, we can specify a type other than a type registered for interface SharedServices.Interfaces.IDoor (i.e., the type of parameter door2). In other words, no matter what bindings are specified for interface SharedServices.Interfaces.IDoor, the object injected for parameter door2 will be of type specified in injectedObject element.

<service type="SharedServices.Interfaces.IRoom" assembly="shared_services">
    <implementation type="SharedServices.Implementations.Room"
                    assembly="shared_services"
                    scope="transient">
        <parameters>
            <object name="door1" type="SharedServices.Interfaces.IDoor"
                    assembly="shared_services"
                    value="5,185.1" />
            <injectedObject name="door2" type="SharedServices.Interfaces.OakDoor"
                            assembly="shared_services" />
        </parameters>
    </implementation>
</service>
Example 3

In the example below, a default constructor will be used to construct an instance of SharedServices.Implementations.Interface8_Impl1, even though type SharedServices.Implementations.Interface8_Impl1 has also a non default constructor. The reason the default constructor is picked is that empty parameters element is used under element implementation.

<service type="SharedServices.Interfaces.IInterface8"
                 assembly="shared_services">
    <implementation type="SharedServices.Implementations.Interface8_Impl1"
                            assembly="shared_services"
                            scope="singleton">

        <parameters>
        </parameters>
    </implementation>
</service>

In the example below, non-default constructor will be used to construct an instance of SharedServices.Implementations.Interface8_Impl1, since no parameters element is used, and the type SharedServices.Implementations.Interface8_Impl1 has both parameter-less constructor as well as constructor with parameters.

<service type="SharedServices.Interfaces.IInterface8"
                 assembly="shared_services">
    <implementation type="SharedServices.Implementations.Interface8_Impl1"
                            assembly="shared_services"
                            scope="singleton">
    </implementation>
</service>
Property Injection
  • IoC.Configuration allows property injection in XML configuration file (for property injection in modules see Type Bindings in IoC.Configuration Modules).
  • The property value is injected using injectedProperties element under element service/implementation or selfBoundService.
  • Normally we should rely on constructor injection. However property injection can be used to handle circular references, when two types reference each other.
  • Property injection is done after the object is constructed. Therefore, the values of properties set by property injection will override the values set by constructor.
Example

In the example below interface SharedServices.Interfaces.IInterface2 is bound to type SharedServices.Implementations.Interface2_Impl3.

  • When type SharedServices.Interfaces.IInterface2 is injected into another type via a constructor or property injection, an instance of SharedServices.Implementations.Interface2_Impl3 will be created and its properties will be set the following way:

    • Property Property1 will be set to a System.Double value de-serialized from textual value 148.3.

    • Property Property2 will be injected by IoC.Configuration, since element injectedObject is used for this property.

    • Property Wheel1 will be set to an instance of SharedServices.Interfaces.IWheel de-serialized from a textual value 27,45.

      Note

      A parameter serializer for type SharedServices.Interfaces.IWheel should exist for type SharedServices.Interfaces.IWheel under element iocConfiguration/parameterSerializers/serializers. See Parameter Serializers for more details on how constructor and property values are de-serialized.

Note

IoC.Configuration will automatically register a self bound service for a type specified in element injectedObject, if the type is not an abstract type or an interface, and if it is not already registered in configuration file. Therefore, no need to register a binding for type SharedServices.Implementations.Interface3_Impl3 used in injectedObject for property Property2, since this type is a non-abstract and non-interface.

Note

Using injectedObject, we can specify a type other than a type registered for type of property Property2 somewhere else. By using element injectedObject we explicitly state the type of the object that should be injected, no matter what types are registered for the type of the property.

Note

The implementation type SharedServices.Implementations.Interface2_Impl3 should have a setter for property Property2, which should be assignable from type SharedServices.Implementations.Interface3_Impl3. However, the setter property is not required in interface SharedServices.Interfaces.IInterface2 specified in service element.

<service type="SharedServices.Interfaces.IInterface2" assembly="shared_services">
    <implementation type="SharedServices.Implementations.Interface2_Impl3"
                                        assembly="shared_services"
                                        scope="singleton">
        <injectedProperties>
            <double name="Property1" value="148.3" />

            <injectedObject name="Property2"
                            type="SharedServices.Implementations.Interface3_Impl3"
                            assembly="shared_services" />
            <object name="Wheel1"
                    type="SharedServices.Interfaces.IWheel"
                    assembly="shared_services" value="27,45" />
        </injectedProperties>
    </implementation>
<service>

Autogenerated Services

Overview

The XML configuration file has two elements autoService and autoServiceCustom to configure bindings for interfaces, for which the implementations are auto-generated.

Element autoService allows specifying interface implementation completely in configuration. Element autoServiceCustom allows specifying an implementation of interface IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator in child element autoServiceCodeGenerator that generates the implementation of autogenerated interface implementation.

Element autoService is easier to setup, however autoServiceCustom allows more control over the generated implementation. The motivation for adding autoServiceCustom was to provide auto-implemented interface implementations based on C# attributes applied to interfaces and interface methods and properties.

Elements autoService and autoServiceCustom can appear in any order under iocConfiguration/dependencyInjection/autoGeneratedServices and iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices elements.

Element autoService
Overview

The XML configuration file has an element autoService that can appear in any order under “iocConfiguration/dependencyInjection/autoGeneratedServices” and “iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices” elements for providing instructions to IoC.Configuration to auto-generate an implementation for an interface.

Note

Refer to IoCConfiguration_autoService.xml and tests in AutoServiceSuccessfulLoadTests.cs for more examples on autoService element.

Consider the interface IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory below, that extends IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactoryBase:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
namespace IoC.Configuration.Tests.AutoService.Services
{
    public interface IActionValidatorFactoryBase
    {
        IReadOnlyList<IActionValidator> GetValidators(int actionTypeId, string projectGuid);
    }

    public interface IActionValidatorFactory : IActionValidatorFactoryBase
    {
        Guid PublicProjectId { get; }
        IActionValidator DefaultActionValidator { get; }
        IReadOnlyList<IActionValidator> GetValidators(ActionTypes actionType, Guid projectGuid);
        void SomeMethodNotInConfigFile(int param1, string param2);
        int SomePropertyNotInConfigFile { get; }
    }
}

We want to configure auto-generation of IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory in configuration file.

However, we are interested only in specifying the auto-generation of properties IActionValidatorFactory.DefaultActionValidator and IActionValidatorFactory.PublicProjectId, as well as in auto-generation of two overloaded methods IActionValidatorFactory.GetValidators(ActionTypes actionType, Guid projectGuid) and IActionValidatorFactoryBase.GetValidators(int actionTypeId, string projectGuid).

We can use child elements autoProperty and autoMethod to specify the implementation of methods and properties in interface IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory and its parents (i.e., in this case IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactoryBase).

IoC.Configuration will generate default implementations for methods and properties, for which no auto-implementation is configured under element autoService. For example method SomeMethodNotInConfigFile() is not configured in example below, so the generated implementation will return default(System.Int32).

Note

More details on autoProperty and autoMethod elements are provided at Element autoProperty and Element autoMethod

  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
<dependencyInjection>
<!--Some other service bindings specified here-->
    <autoGeneratedServices>
        <autoService interface="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory">

            <autoProperty name="DefaultActionValidator"
                          returnType="SharedServices.Interfaces.IActionValidator">
                <injectedObject
                    type="IoC.Configuration.Tests.AutoService.Services.ActionValidatorDefault"/>
            </autoProperty>

            <autoProperty name="PublicProjectId" returnType="System.Guid" >
                <object type="System.Guid" value="95E352DD-5C79-49D0-BD51-D62153570B61"/>
            </autoProperty>

            <autoMethod name="GetValidators"
                        returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]"
                        reuseValue="true">
                <methodSignature>
                    <!--paramName attribute is optional, however it
                    makes the auto-implementation more readable. -->
                    <object paramName="actionType" typeRef="ActionTypes"/>
                    <object paramName="projectGuid" type="System.Guid"/>
                </methodSignature>

                <if parameter1="_classMember:SharedServices.DataContracts.ActionTypes.ViewFilesList"
                    parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
                    <collection>

                        <constructedValue type="SharedServices.Implementations.ActionValidator1">
                            <parameters>
                              <int32 name="intParam" value="7"/>
                            </parameters>
                        </constructedValue>

                        <injectedObject type="SharedServices.Implementations.ActionValidator3" />

                        <!--Plugin1ActionValidator belongs to Plugin1. If we disable this plugin,
                            the injectedObject element below will not be included in
                          returned collection.-->
                        <injectedObject type="TestPluginAssembly1.Implementations.Plugin1ActionValidator"/>
                    </collection>
                </if>

                <if parameter1="_classMember:SharedServices.DataContracts.ActionTypes.ViewFileContents"
                    parameter2="F981F171-B382-4F15-A8F9-FE3732918D3F">
                    <collection>
                        <injectedObject type="SharedServices.Implementations.ActionValidator1" />
                    </collection>
                </if>

                <!--If none of conditions above are true, the default value will be returned by
                interface implementation.-->
                <default>
                    <collection>
                        <!--We can also call a method or property in auto-generated interface, or in
                            one of its base interfaces.-->
                        <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory"
                                     memberName="DefaultActionValidator"/>

                        <injectedObject type="SharedServices.Implementations.ActionValidator3" />

                        <injectedObject type="DynamicallyLoadedAssembly2.ActionValidator4"/>
                    </collection>
                </default>
            </autoMethod>

            <!--Overloaded method GetValidators uses parameters of types System.Int32 and System.string,
                instead of SharedServices.DataContracts.ActionTypes and System.Guid, as in case above.-->
            <autoMethod name="GetValidators"
                        returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]">
                <methodSignature>
                    <!--paramName attribute is optional, however it makes the auto-implementation
                        more readable. -->
                    <int32 paramName="actionTypeId"/>
                    <string paramName="projectGuid" />
                </methodSignature>

                <!-- Attributes parameter1 and parameter2 map values of parameters param1 and param2 in
                    GetInstances() method to returned values. -->
                <if parameter1="0" parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
                    <collection>
                        <injectedObject type="SharedServices.Implementations.ActionValidator3" />
                        <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator4" />
                    </collection>
                </if>

                <default>
                    <collection>
                        <!--We can also call a method or property in auto-generated interface, or
                            in one of its base interfaces.-->
                        <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory"
                                     memberName="DefaultActionValidator"/>
                        <injectedObject type="SharedServices.Implementations.ActionValidator3" />
                        <classMember class="IoC.Configuration.Tests.AutoService.Services.StaticAndConstMembers"
                                     memberName="GetDefaultActionValidator" />
                        <classMember class="IoC.Configuration.Tests.AutoService.Services.IActionValidatorValuesProvider"
                                     memberName="AdminLevelActionValidator"/>
                    </collection>
                </default>
            </autoMethod>
        </autoService>
    </autoGeneratedServices>
</dependencyInjection>
Explanation of autoMethod for method IActionValidatorFactory.GetValidators(…) above

The autoMethod element above for method System.Collections.Generic.IReadOnlyList<SharedServices.Interfaces.IActionValidator> IActionValidatorFactory.GetValidators(ActionTypes actionType, Guid projectGuid) instructs IoC.Configuration to generate such an implementation that:

  • If actionType==SharedServices.DataContracts.ActionTypes.ViewFilesList.ViewFilesList and projectGuid==”8663708F-C707-47E1-AEDC-2CD9291AD4CB”, then collection of three objects will be returned of the following types: SharedServices.Implementations.ActionValidator1, SharedServices.Implementations.ActionValidator3, and TestPluginAssembly1.Implementations.Plugin1ActionValidator.
  • If actionType==SharedServices.DataContracts.ActionTypes.ViewFilesList.ViewFileContents and projectGuid==”F981F171-B382-4F15-A8F9-FE3732918D3F”, then collection of one object will be returned of type SharedServices.Implementations.ActionValidator1.
  • For all other values of parameters, collection of three objects specified under default element will be returned.
Some notes:
  • The service type in autoService element that is specified using attribute interface or interfaceRef should be an interface.

    Note

    Attribute interfaceRef is used to reference a type declared in typeDefinition element.

  • IoC.Configuration will setup a singleton type binding to map the interface specified in autoService element to the auto-generated implementation.

  • To use the autogenerated implementation, just inject the interface (in this case DynamicallyLoadedAssembly2.IActionValidatorFactory1) using constructor or property injection.

  • IoC.Configuration allows configuring auto-implemented properties and methods from the interface specified in autoService element, as well as from any of its parent or ancestor interfaces.

Using auto-generated implementation

Here is an example of using the auto-generated implementation for DynamicallyLoadedAssembly2.IActionValidatorFactory1:

public class TestActionValidatorFactory1
{
    public TestActionValidatorFactory1(
        IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory actionValidatorFactory)
    {
        var actionValidatorsList = actionValidatorFactory.GetValidators(
                                        ActionTypes.ViewFilesList,
                                        Guid.Parse("95E352DD-5C79-49D0-BD51-D62153570B61"))


        Assert.AreEqual(3, actionValidatorsList.Count);
        Assert.IsInstanceOfType(actionValidatorsList[0],
                                typeof(SharedServices.Implementations.ActionValidator1));

        Assert.IsInstanceOfType(actionValidatorsList[1],
                                            typeof(SharedServices.Implementations.ActionValidator3));

        Assert.IsInstanceOfType(actionValidatorsList[2],
                                            typeof(TestPluginAssembly1.Implementations.Plugin1ActionValidator));
    }
}

More details on configuring autoProperty and autoMethod are available at the links below:

Element autoMethod

Element autoMethod is used to configure the auto-generated implementation of a method in interface specified in element autoService.

An example of autoMethod elements is provided in Autogenerated Services. In this section some specifics of this element will be provided.

The format of autoMethod
Method name and return type in autoMethod
  • Method name is specified using the attribute name.

  • Method return value type is specified using the attribute returnType and optional attribute assembly, or alternatively using attribute returnTypeRef to reference a type defined in sole /iocConfiguration/typeDefinitions/typeDefinition element.

    Note

    Even though we only need the method name and signature, to identify the method, the return type makes the configuration more readable. Also, the return type serves as an additional way to identify the method, if a method with similar name and signature exists in multiple extended interfaces.

The example below demonstrates how method name and return type are specified:

1
2
3
4
5
<autoMethod name="GetValidators"
            returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]">

    <!--method signature and return value elements go here...-->
</autoMethod>
Method signature

Child element methodSignature is used to specify the auto-implemented method signature.

If the method has no parameters, no methodSignature element is necessary. Otherwise, this element should be present, which should list the method parameters.

The example below demonstrates how method signature is specified:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!--autoMethod below is a configuration for a C# method
System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator] GetValidators(
                        SharedServices.DataContracts.ActionTypes actionType,
                        System.Guid projectGuid,
                        int someIntParam)-->
<autoMethod name="GetValidators"
            returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]">

    <methodSignature>
        <!--paramName attribute is optional, however it
            makes the auto-implementation more readable. -->
        <object paramName="actionType" typeRef="ActionTypes"/>
        <object paramName="projectGuid" type="System.Guid"/>
        <int32 paramName="someIntParam" />
    </methodSignature>

    <!--return value elements go here..-->
</autoMethod>
Specifying the return values

Return values are specified by using any number of optional if elements, followed by required default element.

  • Specifying a return value using element if

    Element if is used to specify a return value by providing values for up to 10 parameters using attributes parameter1, parameter2, …, parameter10.

    Attribute parameter1 corresponds to the first parameter in methodSignature element, attribute parameter2 corresponds to the second parameter in methodSignature element, and so on.

    The number of parameter attributes should be the same as the number of parameters in element methodSignature.

    The method auto-implemented by IoC.Configuration will return the value specified in child element of if element, if parameters in method call are equal to the values in attributes parameter1, parameter2, etc.

    Note

    The child of if element should be a value initializer element, such as collection, int32, constructedValue, injectedObject, etc. Refer to Value Initialization Elements for more details on value initializer elements.

    The value of parameter attribute is one of the following:

    • A value that will be de-serialized by a parameter serializer to a value of the parameter (example <if parameter1=”15.3”>).

      Note

      Refer to Parameter Serializers for more details on parameter serializers.

      Example (see parameter2 with value “8663708F-C707-47E1-AEDC-2CD9291AD4CB”):

      <!--The generated code will return a collection with two items of types
          SharedServices.Implementations.ActionValidator1 and SharedServices.Implementations.ActionValidator3
          if the first parameter value is SharedServices.DataContracts.ActionTypes.ViewFilesList, and the second parameter
          value is a Guid "8663708F-C707-47E1-AEDC-2CD9291AD4CB" (note, this value will be serialized to System.Guid,
          if the parameter is of type System.Guid).
      -->
      <if parameter1="_classMember:SharedServices.DataContracts.ActionTypes.ViewFilesList"
          parameter2="8663708F-C707-47E1-AEDC-2CD9291AD4CB">
          <collection>
              <injectedObject type="SharedServices.Implementations.ActionValidator1" />
              <injectedObject type="SharedServices.Implementations.ActionValidator3" />
          </collection>
      </if>
      
    • A class member specified by using prefix _classMember followed by class member path. Class member path is the full name of the type (or the type alias for some type defined in iocConfiguration/typeDefinitions/typeDefinition element), followed by class member name.

      Note

      Refer to classMember element for more details on how class members are resolved.

      Note

      Class member can be can be a member in the auto-generated service as well.

      Example (see parameter1 with value “_classMember:ActionTypes.ViewFileContents”):

      <!--The generated code will return a collection with one items of type
          SharedServices.Implementations.ActionValidator1, if the first parameter
          value is SharedServices.DataContracts.ActionTypes.ViewFileContents, and the second parameter
          value is a Guid "F981F171-B382-4F15-A8F9-FE3732918D3F" (note, this value will be serialized to
          System.Guid, if the parameter is of type System.Guid).
      -->
      <if parameter1="_classMember:ActionTypes.ViewFileContents"
          parameter2="F981F171-B382-4F15-A8F9-FE3732918D3F">
          <collection>
              <injectedObject type="SharedServices.Implementations.ActionValidator1" />
          </collection>
      </if>
      
    • A setting value specified by using prefix _settings followed by a setting name. A general, or plugin setting with specified name should exist in configuration file.

      Note

      Refer to Settings or Plugins for more details on general and plugin settings.

      Example (see parameter2 with value “_settings:Project1Guid”):

      <!--The generated code will return a collection with one item of type
          SharedServices.Implementations.ActionValidator3, if the first parameter
          value is SharedServices.DataContracts.ActionTypes.ViewFileContents, and the second parameter
          is equal to the value of setting named **Project1Guid**.
      -->
      <if parameter1="_classMember:ActionTypes.ViewFileContents"
          parameter2="_settings:Project1Guid">
          <collection>
              <injectedObject type="SharedServices.Implementations.ActionValidator3" />
          </collection>
      </if>
      
  • Specifying a return value using element default

    Element default is is used to specify a value to return, if none of the conditions specified in if elements is true, or if no if element is present.

    IoC.Configuration will return the value specified in child of default element.

    Note

    The child of default element should be a value initializer element, such as collection, int32, constructedValue, injectedObject, etc. Refer to Value Initialization Elements for more details on value initializer elements.

    Example:

    <autoService interface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo">
        <!--GetIntValues(): IReadOnlyList<int> GetIntValues(int param1, string param2)-->
        <autoMethod name="GetIntValues" returnType="System.Collections.Generic.IReadOnlyList[System.Int32]" >
            <methodSignature>
                <int32 paramName="param1"/>
                <string paramName="param2"/>
            </methodSignature>
            <if parameter1="1" parameter2="str1">
                <collection>
                    <int32 value="17"/>
                </collection>
            </if>
            <default>
                <collection>
                    <int32 value="18"/>
                    <int32 value="19"/>
                </collection>
            </default>
        </autoMethod>
        <!--Some other autoMethod and autoproperty elements go here-->
    </autoService>
    
Referencing the auto-implemented method parameters

Element parameterValue is used to reference a parameter value in auto-implemented method of auto-generated service.

This element can be used only under elements if or default under element autoMethod.

The element uses an attribute paramName to reference the parameter of auto-generated method. A parameter with this name should be declared under element ../autoService/autoMethod/methodSignature.

Example:

 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
<autoGeneratedServices>
  <!--Demo of referencing auto-implemented method parameters using
      parameterValue element-->
  <autoService
    interface="IoC.Configuration.Tests.AutoService.Services.IAppInfoFactory">

    <autoMethod name="CreateAppInfo"
                returnType="IoC.Configuration.Tests.AutoService.Services.IAppInfo">

      <methodSignature>
        <int32 paramName="appId"/>
        <string paramName="appDescription"/>
      </methodSignature>

      <default>
        <constructedValue
            type="IoC.Configuration.Tests.AutoService.Services.AppInfo">
          <parameters>
            <!--The value of name attribute is the name of constructor parameter
                in AppInfo-->
            <!--
            The value of paramName attribute is the name of parameter in
            IAppInfoFactory.CreateAppInfo.
            This parameter should be present under autoMethod/methodSignature element.
            -->
            <!--In this example the values of name and paramName are similar, however
                they don't have to be.-->
            <parameterValue name="appId" paramName="appId" />
            <parameterValue name="appDescription" paramName="appDescription" />
          </parameters>
        </constructedValue>
      </default>
    </autoMethod>
  </autoService>
</autoGeneratedServices>
Caching the returned values

If constructing the object returned by the function is time consuming, an optional attribute reuseValue in element autoMethod can be used to cache the returned values.

Example:

1
2
3
4
5
6
7
8
9
<autoService
    interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
    <autoMethod name="GetValidators"
                returnTypeRef="IEnumerableOfIResourceAccessValidator"
                reuseValue="true" >
      <!--method signature and return value elements go here...-->
    </autoMethod>
    <!--Some other autoMethod and autoProperty elements go here -->
</autoService>
Resolving conflicts by using declaringInterface in autoMethod

If the auto-implemented method with the specified name, signature, and return type is not in auto-implemented interface, but is present in multiple parent interfaces, IoC.Configuration will report an error, since it will not know which method the configuration refers to.

In such rare cases an attribute declaringInterface can be used to specify explicitly the parent interface, where the method is declared.

Example:

 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
<!--
IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo demonstrates cases
when there are multiple occurrences of auto-generated methods and properties with
same signatures and return types in its base interfaces.
-->
<autoService interface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo">

    <!--GetIntValues(): IReadOnlyList<int> GetIntValues(int param1, string param2)-->
    <autoMethod name="GetIntValues"
                returnType="System.Collections.Generic.IReadOnlyList[System.Int32]" >
        <methodSignature>
            <int32 paramName="param1"/>
            <string paramName="param2"/>
        </methodSignature>
        <if parameter1="1" parameter2="str1">
            <collection>
              <int32 value="17"/>
            </collection>
        </if>
        <default>
            <collection>
                <int32 value="18"/>
                <int32 value="19"/>
            </collection>
        </default>
    </autoMethod>

    <!--
    This method is declared in IMemberAmbiguityDemo_Parent3, which is a base interface for
    IMemberAmbiguityDemo.
    We can provide implementation for this interface, even though it has a similar signature
    and return type as the method
    IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo.GetIntValues.
    By using the attribute 'declaringInterface', we make a distinction between these two.
    -->
    <autoMethod name="GetIntValues"
                returnType="System.Collections.Generic.IReadOnlyList[System.Int32]"
                declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent3">
        <methodSignature>
            <int32 paramName="param1"/>
            <string paramName="param2"/>
        </methodSignature>
        <default>
            <collection>
                <int32 value="3"/>
            </collection>
        </default>
    </autoMethod>
</autoService>
Element autoProperty

Element autoProperty is used to configure the auto-generated implementation of a property in interface specified in element autoService.

An example of autoProperty elements is provided in Autogenerated Services. In this section some specifics of this element will be provided.

The Format of autoProperty
Property name and return type in autoProperty
  • Property name is specified using the attribute name.

  • Property return value type is specified using the attribute returnType and optional attribute assembly, or alternatively using attribute returnTypeRef to reference a type defined in some /iocConfiguration/typeDefinitions/typeDefinition element.

    Note

    Even though we only need the property name, to identify the property, the return type makes the configuration more readable. Also, the return type serves as an additional way to identify the property, if a property with similar name exists in multiple extended interfaces.

Specifying the returned value

The property auto-generated by IoC.Configuration will return the value specified in child of autoProperty element.

The child of autoProperty element should be a value initializer element, such as collection, int32, constructedValue, injectedObject, etc.

Note

Refer to Value Initialization Elements for more details on value initializer elements.

Example:
1
2
3
4
5
<autoService interface="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory">
    <autoProperty name="PublicProjectId" returnType="System.Guid" >
        <object type="System.Guid" value="95E352DD-5C79-49D0-BD51-D62153570B61"/>
    </autoProperty>
</autoService>
Resolving conflicts by using declaringInterface in autoProperty

If the auto-implemented property with the specified name, and return type is not in auto-implemented interface, but is present in multiple parent interfaces, IoC.Configuration will report an error, since it will not know which property the configuration refers to.

In such rare cases an attribute declaringInterface can be used to specify explicitly the parent interface, where the property is declared.

Example:

 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
<!--
IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo demonstrates
cases when there are multiple occurrences of auto-generated methods and properties
with same signatures and return types in base interfaces of
IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo.
-->
<autoService interface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo">
    <!--
    Both IMemberAmbiguityDemo_Parent1 and IMemberAmbiguityDemo_Parent2 have properties called DefaultDbConnection
    with the same return types. We can auto-implement this property for each of these interfaces by using
    declaringInterface attribute in autoProperty element to explicitly specify the interface that own
    the property (declaringInterface can be used in autoMethod as well as demonstrated above)
    -->
    <!--Auto-implementation of IMemberAmbiguityDemo_Parent1.DefaultDbConnection-->
    <autoProperty name="DefaultDbConnection"
                  returnType="SharedServices.Interfaces.IDbConnection"
                  declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent1">
        <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
            <parameters>
                <string name="filePath" value="c:\IMemberAmbiguityDemo_Parent1_Db.sqlite"/>
            </parameters>
        </constructedValue>
    </autoProperty>

    <!--Auto-implementation of IMemberAmbiguityDemo_Parent2.DefaultDbConnection-->
    <autoProperty name="DefaultDbConnection"
                  returnType="SharedServices.Interfaces.IDbConnection"
                  declaringInterface="IoC.Configuration.Tests.AutoService.Services.IMemberAmbiguityDemo_Parent2">
        <constructedValue type="SharedServices.Implementations.SqliteDbConnection">
            <parameters>
                <string name="filePath" value="c:\IMemberAmbiguityDemo_Parent2_Db.sqlite"/>
            </parameters>
        </constructedValue>
    </autoProperty>
</autoService>
Element autoServiceCustom

The XML configuration file has an element autoServiceCustom that can appear under “iocConfiguration/dependencyInjection/autoGeneratedServices” and “iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices” elements.

The autoServiceCustom element specifies the interface that needs to be auto-implemented and has a child element autoServiceCodeGenerator that specifies an implementation of interface IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator.

The implementation of interface IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator is responsible for validating the auto-generated interface and for providing a code for the auto-generating the interface implementation.

See the example below or in test project for more details.

Below is the declaration of IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator.

Click to expand IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator
 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
// Copyright (c) IoC.Configuration Project. All rights reserved.
// Licensed under the MIT License. See LICENSE in the solution root for license information.

using JetBrains.Annotations;
using OROptimizer.DynamicCode;
using OROptimizer.ServiceResolver;
using System;

namespace IoC.Configuration.ConfigurationFile
{
    /// <summary>
    /// Generates an implementation class for interfaces specified in autoServiceCustom element in configuration file.
    /// </summary>
    public interface ICustomAutoServiceCodeGenerator
    {
        /// <summary>
        /// Validates the configuration of "autoServiceCustom" element.
        /// Throws an exception if the configuration is invalid.
        /// </summary>
        /// <param name="customAutoGeneratedServiceInfo"></param>
        void Validate([NotNull] ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo);

        /// <summary>
        /// Generates a C# code for the auto-implemented interface specified in "autoServiceCustom" element.
        /// </summary>
        /// <param name="customAutoGeneratedServiceInfo">Configuration of auto-implemented service configuration.</param>
        /// <param name="dynamicAssemblyBuilder">
        /// An instance of <see cref="IDynamicAssemblyBuilder"/>.
        /// Use methods <see cref="IDynamicAssemblyBuilder.StartDynamicallyGeneratedClass(string, string)"/>,
        /// <see cref="IDynamicAssemblyBuilder.StartDynamicallyGeneratedClass(string, System.Collections.Generic.IEnumerable{string}, string)"/>,
        /// <see cref="IDynamicAssemblyBuilder.AddCSharpFile(string)"/>, etc., to generate the C# code for the implementation.
        /// </param>
        /// <param name="generatedClassNamespace">The generated class namespace.</param>
        /// <param name="generatedClassName">The generated class name without namespace.</param>
        void GenerateCSharp([NotNull] ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo,
            [NotNull] IDynamicAssemblyBuilder dynamicAssemblyBuilder,
            [NotNull] string generatedClassNamespace, [NotNull] string generatedClassName);

        /// <summary>
        /// Validates the configuration of "autoServiceCustom" element after the IoC container is loaded.
        /// Throws an exception if the configuration is invalid.
        /// </summary>
        /// <param name="diContainer">The IoC container. Use IDiContainer.<see cref="IServiceResolver.Resolve(Type)"/> to resolve types.</param>
        /// <param name="customAutoGeneratedServiceInfo">Information about auto-implemented interface.</param>
        void ValidateOnIoCContainerLoaded([NotNull] DiContainer.IDiContainer diContainer, [NotNull] ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo);
    }
}

The motivation for adding autoServiceCustom was to provide an auto-implemented interface implementation based on C# attributes applied to the interface and in interface and interface methods and properties.

For example one such scenario when autoServiceCustom might be handy is when we want to auto-implement interfaces for object relational mapping, when interfaces represent database tables, and are decorated with metadata attributes that describe the database schema.

In this case, an implementation of IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator can scan the attributes applied to an interface and interface methods and properties, and generate an implementation of an interface based on metadata attributes.

The tests in IoC.Configuration.Tests.AutoServiceCustom.AutoServiceCustomSuccessfulLoadTests.cs demonstrate an example of auto-generated repository interface implementations based on attributes applied to the interface.

Below is a simple example of setting up custom auto-service in configuration file (a segment copied from configuration file DemoIoCConfiguration_autoServiceCustom.xml.

 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
<dependencyInjection>
    <modules>
    </modules>

    <services>
    </services>

    <autoGeneratedServices>

       <!--Interface specified in autoServiceCustom is auto-implemented by implementation of
       IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository.RepositoryInterfaceImplementationGenerator
       that is specified in autoServiceCodeGenerator element.-->

        <autoServiceCustom interface="IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface1">
            <autoServiceCodeGenerator>
                    <constructedValue typeRef="DemoCustomAutoServiceCodeGenerator">
                            <parameters>
                                    <classMember name="connectionString"
                                        classRef="ConnectionStrings"
                                        memberName="ConnectionString1" />
                            </parameters>
                    </constructedValue>
            </autoServiceCodeGenerator>
        </autoServiceCustom>

            <autoServiceCustom interface="IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface2">
                    <autoServiceCodeGenerator>
                            <constructedValue typeRef="DemoCustomAutoServiceCodeGenerator">
                                    <parameters>
                                            <classMember name="connectionString"
                                                classRef="ConnectionStrings"
                                                memberName="ConnectionString1" />
                                    </parameters>
                            </constructedValue>
                    </autoServiceCodeGenerator>
            </autoServiceCustom>
    </autoGeneratedServices>
</dependencyInjection>

This configuration instructs IoC.Configuration to generate an implementation of interfaces IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface1.cs and IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface2.cs using class IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.DemoCustomAutoServiceCodeGenerator.cs specified in child element autoServiceCodeGenerator.

Below is the code in IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.DemoCustomAutoServiceCodeGenerator.

 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using IoC.Configuration.ConfigurationFile;
using IoC.Configuration.DiContainer;
using IoC.Configuration.Tests.AutoServiceCustom.SimpleDataRepository;
using NUnit.Framework;
using OROptimizer;
using OROptimizer.DynamicCode;
using SharedServices.Interfaces;

namespace IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom;

/// <summary>
/// This is a simple demo to demonstrate an implementation of <see cref="ICustomAutoServiceCodeGenerator"/>.
/// For a better example reference <see cref="RepositoryInterfaceImplementationGenerator"/> used in tests
/// in AutoServiceCustom.
/// The best use of <see cref="ICustomAutoServiceCodeGenerator"/> is to generate interface implementation based
/// on attributes applied to interface and interface methods (such as auto-generating entity framework interfaces based on
/// table names, and column metadata attributes).
/// </summary>
public class DemoCustomAutoServiceCodeGenerator : ICustomAutoServiceCodeGenerator
{
    public DemoCustomAutoServiceCodeGenerator(string connectionString)
    {
        // Demo passing parameters to ICustomAutoServiceCodeGenerator in configuration file.
        Assert.AreEqual(ConnectionStrings.ConnectionString1, connectionString);
    }

    /// <inheritdoc />
    public void Validate(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo)
    {
        var implementedInterfaceType = customAutoGeneratedServiceInfo.ImplementedInterface;

        if (!implementedInterfaceType.IsInterface ||
            implementedInterfaceType.GetInterfaces().Length > 0 ||
            implementedInterfaceType.GetMethods().Length != 1 ||
            implementedInterfaceType.GetProperties().Length != 0)
            throw new Exception($"The demo auto-implemented interface should not have a parent interfaces and should have exactly one method.");

        var methodInfo = implementedInterfaceType.GetMethods().First();

        if (methodInfo.GetParameters().Length != 0 || methodInfo.ReturnType != typeof(int))
            throw new Exception($"The demo auto-implemented method should be veryyy simple to be short!!.");

        if (methodInfo.GetCustomAttributes().FirstOrDefault(x => x is SimpleMethodMetadataAttribute) == null)
            throw new Exception($"Method should have an attribute of type '{typeof(SimpleMethodMetadataAttribute)}'.");
    }

    /// <inheritdoc />
    public void GenerateCSharp(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo, IDynamicAssemblyBuilder dynamicAssemblyBuilder, string generatedClassNamespace, string generatedClassName)
    {
        // Use IDynamicAssemblyBuilder.AddReferencedAssembly(string assemblyPath) or
        // IDynamicAssemblyBuilder.AddReferencedAssembly(Type typeInAssembly) to add assemblies that will be
        // referenced by auto-generated assembly if types in these assemblies are used in auto-generated code.
        dynamicAssemblyBuilder.AddReferencedAssembly(Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"));
        dynamicAssemblyBuilder.AddReferencedAssembly(typeof(IInterface1));

        // By now Validate(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo) already validated
        // that a single method with attribute is present in interface.
        var methodInfo = customAutoGeneratedServiceInfo.ImplementedInterface.GetMethods().First();

        var attribute = (SimpleMethodMetadataAttribute)methodInfo.GetCustomAttributes().FirstOrDefault(x => x is SimpleMethodMetadataAttribute);

        var dynamicClass = dynamicAssemblyBuilder.StartDynamicallyGeneratedClass(generatedClassName,
            new[]
            {
                customAutoGeneratedServiceInfo.ImplementedInterface.GetTypeNameInCSharpClass()
            },
            generatedClassNamespace);

        var methodData = dynamicClass.StartInterfaceImplementationMethod(methodInfo, false);

        methodData.AddCodeLine("{");

        methodData.AddCodeLine("var testReferencedAssembly = new DynamicallyLoadedAssembly1.Dog(40);");

        methodData.AddCodeLine($"return {attribute.ReturnedValue};");
        methodData.AddCodeLine("}");
    }

    /// <inheritdoc />
    public void ValidateOnIoCContainerLoaded(IDiContainer diContainer, ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo)
    {
        // At this point the DI container diContainer is loaded. Do validation using some services in container
        // and throw an exception if necessary
        //diContainer.Resolve()
    }
}

Look at test class below for an example of setting up and initializing the DI container from configuration file, and resolving and using auto-generated interfaces IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface1.cs and IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface2.cs.

 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
56
57
58
59
60
61
62
63
64
// Copyright (c) IoC.Configuration Project. All rights reserved.
// Licensed under the MIT License. See LICENSE in the solution root for license information.

using System.IO;
using IoC.Configuration.DiContainerBuilder;
using IoC.Configuration.DiContainerBuilder.FileBased;
using NUnit.Framework;
using OROptimizer.Utilities.Xml;
using TestsSharedLibrary;

namespace IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom;

[TestFixture]
public class DemoAutoServiceCustom
{
    private static IContainerInfo _containerInfo;

    [SetUp]
    public static void TestSetUp()
    {
        TestsHelper.SetupLogger();

        var fileBasedConfigurationParameters = new FileBasedConfigurationParameters(
            new FileBasedConfigurationFileContentsProvider(
                Path.Combine(Helpers.TestsEntryAssemblyFolder, @"DocumentationTests\AutoServiceCustom\DemoIoCConfiguration_autoServiceCustom.xml")),
            Helpers.TestsEntryAssemblyFolder,
            // LoadedAssembliesForTests is an implementation of ILoadedAssemblies that has a method
            // "IEnumerable<Assembly> GetAssemblies()" that returns list of assemblies to add as references to
            // generate dynamic assembly.
            new LoadedAssembliesForTests())
        {
            AdditionalReferencedAssemblies = new []
            {
                // List additional assemblies that should be added to dynamically generated assembly as references
                Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"),
                Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly2.dll")
            },
            AttributeValueTransformers = new[] {new FileFolderPathAttributeValueTransformer()},
            ConfigurationFileXmlDocumentLoaded = (sender, e) =>
                Helpers.EnsureConfigurationDirectoryExistsOrThrow(e.XmlDocument.SelectElement("/iocConfiguration/appDataDir").GetAttribute("path"))
        };

        _containerInfo = new DiContainerBuilder.DiContainerBuilder()
            .StartFileBasedDi(fileBasedConfigurationParameters, out _)
            .WithoutPresetDiContainer()
            .RegisterModules().Start();
    }

    [Test]
    public void Demo()
    {
        var simpleAutoImplementedInterface1 = _containerInfo.DiContainer.Resolve<ISimpleAutoImplementedInterface1>();
        Assert.AreEqual(10, simpleAutoImplementedInterface1.GetValue());

        var simpleAutoImplementedInterface2 = _containerInfo.DiContainer.Resolve<ISimpleAutoImplementedInterface2>();
        Assert.AreEqual(20, simpleAutoImplementedInterface2.GetSomeOtherValue());
    }

    [TearDown]
    public static void TestTeaDown()
    {
        _containerInfo.Dispose();
    }
}

Value Initialization Elements

Value initialization elements are elements that are used to specify values in different contexts. Some examples are using elements like int32, constructedValue, injectedObject, object, or constructedValue to specify constructor parameter value, or a value to returned in autoMethod or autoProperty elements.

Value initialization elements normally have attributes or child elements to specify the value, and might have some additional attributes, based on the type of the element and the context, where the element is used.

For example, if the value initialization element is used to specify injected property or constructor parameter value, the element should have a name attribute, to specify the constructor parameter or property name.

On the other hand, if the element is used to specify a returned value in autoMethod or autoProperty element, no name attribute should be present.

Predefined Type Value Initializer Elements

Predefined type value elements are elements used to provide values for some predefined types, such as System.Int32, System.Double, System.DateTime, etc.

These elements have a name, that reflects the type of the value being specified (e.g., <int32>, <datetime>, etc).

The value specified in value attribute in these elements is serialized/deserialized using one of the classes in package OROptimizer.Shared, that implement OROptimizer.Serializer.ITypeBasedSimpleSerializer.

Note

Refer to Parameter Serializers for more details on parameter serializers.

For example the value specified in element datetime is serialized using serialized/deserialized using the class OROptimizer.Serializer.TypeBasedSimpleSerializerDateTime.

The serializers used to serialize/deserialize the value in value element can be replaced, by specifying a different serializer in element iocConfiguration/parameterSerializers/serializers/parameterSerializer (see Parameter Serializers).

Note

To see the serializers loaded by IoC.Configuration for different types, run the IoC.Configuration with logging level set to INFO.

The following is the overview of predefined value initialization elements:

  • byte: Used to specify values of type System.Byte.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerByte.
  • int16: Used to specify values of type System.Int16.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerShort.
  • int32: Used to specify values of type System.Int32.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerInt.
  • int64: Used to specify values of type System.Int64.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerLong.
  • double: Used to specify values of type System.Double.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerDouble.
  • datetime: Used to specify values of type System.DateTime.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerLong.
  • boolean: Used to specify values of type System.Boolean.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerBoolean.
  • string: Used to specify values of type System.String.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerString.
  • datetime: Used to specify values of type System.DateTime.
    The serializer class is OROptimizer.Serializer.TypeBasedSimpleSerializerLong.
Example 1: Using double and datetime elements as service implementation constructor parameters
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<service type="SharedServices.Interfaces.IInterface2" >
    <!--Test constructor parameters-->
    <implementation type="SharedServices.Implementations.Interface2_Impl1"
                    scope="singleton">
      <parameters>
        <datetime name="param1" value="2014-10-29 23:59:59.099" />
        <double name="param2" value="125.1" />
        <injectedObject name="param3"
                        type="SharedServices.Interfaces.IInterface3" />
      </parameters>
    </implementation>
</service>
Example 2: Using int32 element to specify a return value in autoProperty element
1
2
3
4
5
<autoService interfaceRef="IProjectIds" >
    <autoProperty name="DefaultProjectId" returnType="System.Int32">
        <int32 value="1"/>
    </autoProperty>
</autoService>
Example 2: int32, double, and string elements in settings element
1
2
3
4
5
<settings>
    <int32 name="SynchronizerFrequencyInMilliseconds" value="5000" />
    <double name="MaxCharge" value="155.7" />
    <string name="DisplayValue" value="Some display value" />
</settings>

object element

Element object is used to specify a value by using value attribute, that is de-serialize by a serializer specified in iocConfiguration/parameterSerializers/serializers/parameterSerializer elements.

Note

Refer to Parameter Serializers for more details on parameter serializers.

Note

IoC.Configuration provides default parameter serializers for some types. The types for which parameter serializers are provided out of the box are:
System.Byte, System.Int16, System.Int32, System.Int64, System.Double, System.Boolean, System.DateTime, System.String, and System.Guid.
Example 1: Using object element in settings element
1
2
3
4
5
6
<settings>
    <object name="Project1Guid" typeRef="Guid"
            value="EA91B230-3FF8-43FA-978B-3261493D58A3" />
    <object name="Project2Guid" typeRef="Guid"
            value="9EDC7F1A-6BD6-4277-9015-5A9277218681" />
</settings>
Example 2: Using object element to specify a returned value in autoProperty and autoMethod elements
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<autoGeneratedServices>
    <autoService interfaceRef="IProjectGuids" >
        <autoProperty name="Project1" returnTypeRef="Guid">
            <object typeRef="Guid"
                    value="966FE6A6-76AC-4895-84B2-47E27E58FD02"/>
        </autoProperty>

        <autoMethod name="GetDefaultProject"
                    returnTypeRef="Guid">
            <default>
                <object typeRef="Guid"
                        value="1E08071B-D02C-4830-AE3C-C9E78A29EA37"/>
            </default>
        </autoMethod>
    </autoService>
<autoGeneratedServices>
Example 3: Using object element to specify constructor and injected property values for service implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<service type="TestPluginAssembly1.Interfaces.IRoom">
    <implementation type="TestPluginAssembly1.Implementations.Room" scope="transient">
        <parameters>
            <object name="door1" type="TestPluginAssembly1.Interfaces.IDoor"
                    value="5,185.1" />
            <injectedObject name="door2"
                            type="TestPluginAssembly1.Interfaces.IDoor" />
        </parameters>
        <injectedProperties>
            <object name="Door2"
                    type="TestPluginAssembly1.Interfaces.IDoor"
                    value="7,187.3" />
        </injectedProperties>
    </implementation>
</service>

injectedObject element

Element injectedObject can be used to specify a value that will be injected by IoC.Configuration.

The type to inject is specified using either type attribute (and optional assembly attribute), or typeRef attribute.

If the type to inject is non-abstract and non-interface, and has a public constructor, IoC.Configuration will create a binding for the type.

Otherwise, a binding for the type should be specified either in configuration file, or in one of the loaded IoC modules.

Example 1: Using injectedObject element to specify service implementation constructor parameter value
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<service type="SharedServices.Interfaces.IInterface2" >
    <implementation type="SharedServices.Implementations.Interface2_Impl1"
                    scope="singleton">
        <parameters>
            <datetime name="param1" value="2014-10-29 23:59:59.099" />
            <double name="param2" value="125.1" />
            <injectedObject name="param3"
                            type="SharedServices.Interfaces.IInterface3" />
        </parameters>
    </implementation>
</service>
Example 2: Using injectedObject element to specify injected property value in service implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<service type="SharedServices.Interfaces.IInterface2" >
    <implementation type="SharedServices.Implementations.Interface2_Impl2"
                    scope="singleton">
        <injectedProperties>
          <datetime name="Property1"
                    value="1915-04-24 00:00:00.001" />
          <double name="Property2" value="365.41" />
          <injectedObject name="Property3"
                          type="SharedServices.Interfaces.IInterface3" />
        </injectedProperties>
    </implementation>
</service>
Example 2: Using injectedObject element to specify a returned value in autoProperty element
1
2
3
4
5
6
7
<autoService interface="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory">
    <autoProperty name="DefaultActionValidator"
                  returnType="SharedServices.Interfaces.IActionValidator">
      <injectedObject
            type="IoC.Configuration.Tests.AutoService.Services.ActionValidatorDefault"/>
    </autoProperty>
</autoService>

collection element

Collection element is used to specify collection values.

Based on the context, in which collection element is used, it might use collectionType and itemType attributes to specify collection type and collection items type, or these values will be derived by IoC.Configuration.

Note

The possible values of collectionType attribute currently are enumerable, list, readOnlyList, and array.

For example, if collection is used to specified as a constructor parameter, or injected property value, collectionType and itemType attributes are required, along with the name attribute.

On the other hand, if collection is used to provide a return value in autoProperty or autoMethod elements, this attributes are not used, and IoC.Configuration determines the type of the collection from the auto-generated property or method return type.

Note

Refer to IoCConfiguration_collection.xml for more examples on collection element.

Example 1: Using collection element to specify constructed parameter value in service implementation
 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
<services>
    <selfBoundService
        type="IoC.Configuration.Tests.Collection.Services.CollectionsTestClass1"
        scope="singleton" >

        <parameters>
            <!--Demo of collection element used as a constructor parameter.-->
            <collection name="readOnlyListParam"
                        collectionType="readOnlyList"
                        itemType="System.Int32">
              <int32 value="17"/>
              <int32 value="24"/>
              <int32 value="27"/>
            </collection>

            <!--Demo of collection element used as a constructor parameter.-->
            <collection name="arrayParam"
                        collectionType="array"
                        itemTypeRef="IInterface1">
              <injectedObject typeRef="IInterface1"/>
              <constructedValue typeRef="Interface1_Impl">
                <parameters>
                  <int32 name="param1" value="29"/>
                </parameters>
              </constructedValue>
            </collection>
        </parameters>
    </selfBoundService>
<services>
Example 2: Using collection element to specify injected property value
 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
<services>
    <selfBoundService
        type="IoC.Configuration.Tests.Collection.Services.CollectionsTestClass1"
        scope="singleton" >

        <injectedProperties>
            <!--Demo of collection element used to initialize
                the value of injected property.-->
            <collection name="EnumerableValues"
                        collectionType="enumerable"
                        itemType="SharedServices.Interfaces.IInterface1" >
              <constructedValue typeRef="Interface1_Impl">
                <parameters>
                  <int32 name="param1" value="18"/>
                </parameters>
              </constructedValue>
              <settingValue settingName="DefaultInterface1Value"/>
              <injectedObject typeRef="IInterface1"/>
            </collection>

            <!--Demo of collection element used to initialize
                the value of injected property.-->
            <collection name="ListValues"
                        collectionType="list"
                        itemTypeRef="IInterface1">
              <injectedObject typeRef="IInterface1"/>
              <settingValue settingName="DefaultInterface1Value"/>
              <constructedValue typeRef="Interface1_Impl">
                <parameters>
                  <int32 name="param1" value="139"/>
                </parameters>
              </constructedValue>
            </collection>
        </injectedProperties>
    </selfBoundService>
<services>
Example 3: Using collection element to specify a returned value for auto-generated method
 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
<autoGeneratedServices>
    <!--Demo of collection element used in auto-implemented method and property
        return values.-->
    <autoService interface="IoC.Configuration.Tests.Collection.Services.IAutoService1">
        <autoMethod name="GetAllActionIds"
                    returnType="System.Collections.Generic.IReadOnlyList[System.Int32]">
            <methodSignature>
                <int32 paramName="appId"/>
            </methodSignature>
            <if parameter1="3">
                <collection>
                    <int32 value="27"/>
                    <int32 value="17"/>
                </collection>
            </if>
            <default>
              <collection>
                <int32 value="13"/>
                <int32 value="27"/>
                <int32 value="17"/>
              </collection>
            </default>
        </autoMethod>
    </autoService>
</autoGeneratedServices>
Example 4: Using collection element to provide a service implementation
 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
<service type="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IDbConnection]">
    <valueImplementation scope="singleton">
        <collection>
            <settingValue settingName="DefaultDBConnection"/>

            <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
                <parameters>
                    <string name="serverName" value="SQLSERVER2012"/>
                    <string name="databaseName" value="DB1"/>
                    <string name="userName" value="user1"/>
                    <string name="password" value="password123"/>
                </parameters>
            </constructedValue>

            <constructedValue type="SharedServices.Implementations.SqlServerDbConnection">
                <parameters>
                    <string name="serverName" value="SQLSERVER2016"/>
                    <string name="databaseName" value="DB2"/>
                    <string name="userName" value="user2"/>
                    <string name="password" value="password456"/>
                </parameters>
            </constructedValue>

            <constructedValue type="TestPluginAssembly1.Implementations.MySqlDbConnection">
                <parameters>
                    <string name="connectionString" value="user=User1;password=123"/>
                </parameters>
            </constructedValue>
        </collection>
    </valueImplementation>
</service>

constructedValue element

The constructedValue element is used to construct a value in configuration file.

The constructedValue element can be used recursively in another constructedValue to specify the constructor parameter or injected property values.

Note

Refer to IoCConfiguration_constructedValue.xml for more examples on constructedValue element.

Below are some examples of using constructedValue element.

Example 1: Using constructedValue element to define a setting of type IoC.Configuration.Tests.ConstructedValue.Services.AppInfo
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<settings>
    <object name="App1" typeRef="IAppInfo" value="1, App 1"/>

    <!--AppInfo is declared in element typeDefinitions, and references a type
        IoC.Configuration.Tests.ConstructedValue.Services.AppInfo. -->
    <constructedValue name="App2" typeRef="AppInfo" >
        <parameters>
          <int32 name="Id" value="2"/>
        </parameters>
        <injectedProperties>
          <string name="Description" value="App 2"/>
        </injectedProperties>
    </constructedValue>
</settings>
Example 2: Using constructedValue element to define a service implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<services>
    <service typeRef="IAppInfo">
        <valueImplementation scope="singleton">
            <!--Demo of constructedValue to provide an implementation
                for a service under valueImplementation element.-->
            <constructedValue typeRef="AppInfo">
                <parameters>
                  <int32 name="id" value="8"/>
                </parameters>
                <injectedProperties>
                  <string name="Description" value="App 8"/>
                </injectedProperties>
            </constructedValue>
        </valueImplementation>
    </service>
</services>
Example 3: Using constructedValue element to specify a value returned in autoProperty element
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<autoGeneratedServices>
    <autoService interface="IoC.Configuration.Tests.ConstructedValue.Services.IAppInfoFactory">
        <autoProperty name="DefaultAppInfo" returnTypeRef="IAppInfo">
            <constructedValue typeRef="AppInfo" >
                <parameters>
                    <int32 name="id" value="11"/>
                </parameters>
                <injectedProperties>
                    <string name="Description" value="App 11"/>
                </injectedProperties>
            </constructedValue>
        </autoProperty>
    </autoService>
</autoGeneratedServices>
Example 4: Using constructedValue element to specify a value returned in autoMethod element
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<autoGeneratedServices>
    <autoService interface="IoC.Configuration.Tests.ConstructedValue.Services.IAppInfoFactory">
        <autoMethod name="CreateAppInfo" returnTypeRef="IAppInfo">
            <default>
                <constructedValue  typeRef="AppInfo" >
                    <parameters>
                        <int32 name="id" value="12"/>
                    </parameters>
                    <injectedProperties>
                        <string name="Description" value="App 12"/>
                    </injectedProperties>
                </constructedValue>
            </default>
        </autoMethod>
    </autoService>
</autoGeneratedServices>
Example 5: Using constructedValue element as a parameter value in another constructedValue element
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<settings>
    <constructedValue
            name="DecoratedAppInfo"
            type="IoC.Configuration.Tests.ConstructedValue.Services.AppInfoDecorator">
        <parameters>
            <constructedValue
                    name="appInfo"
                    type="IoC.Configuration.Tests.ConstructedValue.Services.AppInfoDecorator">
                <parameters>
                    <constructedValue name="appInfo" typeRef="AppInfo">
                        <parameters>
                            <int32 name="id" value="25"/>
                        </parameters>
                        <injectedProperties>
                            <string name="Description" value="App 25"/>
                        </injectedProperties>
                    </constructedValue>
                </parameters>
            </constructedValue>
        </parameters>
    </constructedValue>
</settings>

settingValue element

The settingValue allows referencing a setting value in configuration file.

Note

For more details on settings see Settings.

Note

Refer to IoCConfiguration_settingValue_ReferencingInConfiguration.xml for more examples on settingValue element.

Example 1: Using settingValue element to provide a service implementation
1
2
3
4
5
6
 <service type="System.Int32">
    <valueImplementation scope="transient">
      <!--Demo of using a setting value in valueImplementation.-->
      <settingValue settingName="defaultInt"/>
    </valueImplementation>
 </service>
Example 2: Using settingValue element in collection element
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 <service type="System.Collections.Generic.IReadOnlyList[System.Int32]">
    <valueImplementation scope="singleton">
        <collection>
            <!--Example of using setting value in collection element-->
            <settingValue settingName="defaultInt"/>
            <settingValue settingName="app1"/>
            <int32 value="78"/>
        </collection>
    </valueImplementation>
 </service>
Example 3: Using settingValue element to specify constructor parameter and injected property values
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<service type="IoC.Configuration.Tests.SettingValue.Services.IAppInfo" >
    <implementation type="IoC.Configuration.Tests.SettingValue.Services.AppInfo" scope="transient">
        <parameters>
            <!--Demo of using settingValue to inject value into an implementation constructor.-->
            <settingValue name="appId" settingName="defaultAppId"/>
        </parameters>
        <injectedProperties>
            <!--Demo of using settingValue to inject value into an implementation property.-->
            <settingValue name="AppDescription" settingName="defaultAppDescr"/>
        </injectedProperties>
    </implementation>
</service>
Example 4: Referencing setting values in autoMethod and autoProperty elements
 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
<autoGeneratedServices>
    <autoService interface="IoC.Configuration.Tests.SettingValue.Services.IAppIds">
        <autoMethod name="GetAppIds"
                    returnType="System.Collections.Generic.IReadOnlyList[System.Int32]">
            <methodSignature>
                <string paramName="platformType"/>
            </methodSignature>

            <!--Demo of using the value of setting named "android" in if condition
                in autoMethod-->
            <if parameter1="_settings:android">
                <collection>
                    <!--Demo of setting value used as one of returned values in
                    autoMethod if element.-->
                    <settingValue settingName="defaultAppId"/>
                    <settingValue settingName="app1"/>
                    <int32 value="9"/>
                </collection>
            </if>

            <default>
              <collection>
                <!--Demo of setting value used as one of returned values in
                    autoMethod default element.-->
                <settingValue settingName="defaultAppId"/>
                <int32 value="8"/>
              </collection>
            </default>
        </autoMethod>

        <autoProperty name="MainAppId" returnType="System.Int32">
            <!--Demo of setting value used as return value of autoProperty element.-->
            <settingValue settingName="defaultAppId"/>
        </autoProperty>
    </autoService>
</autoGeneratedServices>
Example 5: Referencing setting value in if element under autoMethod element
 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
<autoService interface="IoC.Configuration.Tests.AutoService.Services.IActionValidatorFactory">

    <autoMethod name="GetValidators"
                    returnType="System.Collections.Generic.IReadOnlyList[SharedServices.Interfaces.IActionValidator]"
                    reuseValue="true">

        <methodSignature>
          <object paramName="actionType" typeRef="ActionTypes"/>
          <object paramName="projectGuid" type="System.Guid"/>
        </methodSignature>

        <!--Use _classMember: prefix in if elements to reference class member in if
            condition in auto-implemented method.-->
        <if parameter1="_classMember:ActionTypes.ViewFileContents" parameter2="_settings:Project1Guid">
            <collection>
                <injectedObject type="IoC.Configuration.Tests.AutoService.Services.ActionValidator1" />
            </collection>
        </if>

        <default>
            <collection>
                <injectedObject type="SharedServices.Implementations.ActionValidator3" />
                <injectedObject type="DynamicallyLoadedAssembly2.ActionValidator4"/>
            </collection>
        </default>
    </autoMethod>
<autoService>

classMember element

The classMember element is used to reference class member values (i.e., class variables, constant values, properties, method call results) in configuration file.

This element uses attribute class (and optional attribute assembly), or alternatively, an attribute classRef to specify the class, as well as attribute memberName, to specify the class member name.

The element classMember can be used to reference enum values as well. Example: <classMember class=”SharedServices.DataContracts.ActionTypes” memberName=”ViewFilesList” />.

Referencing non-static and non-constant class members

If the class member is non-static, and non-constant, IoC.Configuration will get the class member value by first resolving the class instance from the dependency injection container.

If the class is non-interface, non-abstract, and has a public constructor, IoC.Configuration will generate a self-binding for the class.

Otherwise, a binding should be provided either in configuration file, or in one of dependency injection modules.

Note

Refer to IoCConfiguration_classMember.xml for more examples on classMember element.

Example 1: Using classMember to provide a service implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<service type="System.Int32">
    <valueImplementation scope="singleton">
      <!--Example of classMember in valueImplementation.
      Since IAppIds.DefaultAppId is non-static,
      IAppIds will be resolved from dependency injection container, and the
      value of property DefaultAppId of resolved object will be bound
      to System.Int32
      -->
        <classMember classRef="IAppIds" memberName="DefaultAppId" />
    </valueImplementation>
</service>
Example 2: Using classMember in collection element
1
2
3
4
5
6
7
8
9
<service type="System.Collections.Generic.IReadOnlyList[System.Int32]" >
    <valueImplementation scope="singleton">
        <collection>
            <!--Demo of classMember in collection element.-->
            <classMember classRef="ConstAndStaticAppIds" memberName="AppId1"/>
            <classMember classRef="IAppIds" memberName="DefaultAppId"/>
        </collection>
    </valueImplementation>
</service>
Example 3: Using classMember to specify a returned value in autoProperty element
1
2
3
4
5
6
7
8
9
<autoGeneratedServices>

    <!--The scope for autoService implementations is always singleton -->
    <autoService interfaceRef="IAppIds">
        <autoProperty name="DefaultAppId" returnType="System.Int32">
            <!--Example of using classMember attribute in auto property.-->
            <classMember class="System.Int32" memberName="MaxValue"/>
        </autoProperty>
    </autoService>
Example 3: Referencing class member in if element under autoMethod element

To reference class members in if element attributes in autoMethod, use _classMember: prefix followed by class full name (or type alias name, for a type declared in typeDefinition element), period, and the class member name.

Note

Refer to Autogenerated Services and Element autoMethod for more details on autoMethod element.

In the example below, we reference a class member IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId (it is assumed that the configuration has a typeDefinition element for a type IoC.Configuration.Tests.ClassMember.Services.IAppIds, that has an alias IAppIds)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<autoService interface="IoC.Configuration.Tests.ClassMember.Services.IAppIdToPriority">
    <autoMethod name="GetPriority" returnType="System.Int32">
        <methodSignature>
            <int32 paramName="appId"/>
        </methodSignature>

        <!--Property IoC.Configuration.Tests.ClassMember.Services.IAppIds.DefaultAppId
            is non-static, therefore IoC.Configuration.Tests.ClassMember.Services.IAppIds
            will be resolved from dependency injection container, and the value of property
            DefaultAppId in resolved object will be used in if condition-->
        <if parameter1="_classMember:IAppIds.DefaultAppId">
            <int32 value="14" />
        </if>

        <default>
            <int32 value="1"/>
        </default>
    </autoMethod>
</autoService>
Example 3: Using classMember to call methods with parameters

If the class member is a method, we can use parameters child element to specify parameter values when the method is called.

See the usage of classMember elements in the example below.

 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
<autoService interface="IoC.Configuration.Tests.ClassMember.Services.IAppInfos">
  <autoProperty name="AllAppInfos"
      returnType="System.Collections.Generic.IReadOnlyList[....Services.IAppInfo]" >
    <collection>
      <!--
      An example of calling a non static factory method to create an instance of
      IAppInfo. Since method IAppInfoFactory.CreateAppInfo(appId, appDescription)
      is non-static, an instance of IAppInfoFactory will be resolved using the DI
      container.
      Also, since IAppInfoFactory is an interface, a binding for IAppInfoFactory
      should be configured in configuration file or in some module.
      -->
      <classMember class="...Tests.ClassMember.Services.IAppInfoFactory"
                   memberName="CreateAppInfo">
        <parameters>
          <int32 name="appId" value="1258"/>
          <string name="appDescription"
                  value="App info created with non-static method call."/>
        </parameters>
      </classMember>
      <!--
      An example of calling a static factory method to create an instance
      of IAppInfo.
      -->
      <classMember class="....Tests.ClassMember.Services.StaticAppInfoFactory"
                   memberName="CreateAppInfo">
        <parameters>
          <int32 name="appId" value="1259"/>
          <string name="appDescription"
                  value="App info created with static method call."/>
        </parameters>
      </classMember>
    </collection>
  </autoProperty>
</autoService>

parameterValue element

Element parameterValue is used to reference a parameter value in auto-implemented method of auto-generated service.

This element can be used only under elements if or default under element autoMethod.

Note

Refer to Autogenerated Services for more details on auto-generated services.

The element uses an attribute paramName to reference the parameter of auto-generated method. A parameter with this name should be declared under element ../autoService/autoMethod/methodSignature.

An example below demonstrated an example of using an element parameterValue.

 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
<autoGeneratedServices>
  <!--Demo of referencing auto-implemented method parameters using
      parameterValue element-->
  <autoService
    interface="IoC.Configuration.Tests.AutoService.Services.IAppInfoFactory">

    <autoMethod name="CreateAppInfo"
                returnType="IoC.Configuration.Tests.AutoService.Services.IAppInfo">
      <methodSignature>
        <int32 paramName="appId"/>
        <string paramName="appDescription"/>
      </methodSignature>

      <default>
        <constructedValue
            type="IoC.Configuration.Tests.AutoService.Services.AppInfo">
          <parameters>
            <!--The value of name attribute is the name of constructor parameter
                in AppInfo-->
            <!--
            The value of paramName attribute is the name of parameter in
            IAppInfoFactory.CreateAppInfo.
            This parameter should be present under autoMethod/methodSignature element.
            -->
            <!--In this example the values of name and paramName are similar, however
                they don't have to be.-->
            <parameterValue name="appId" paramName="appId" />
            <parameterValue name="appDescription" paramName="appDescription" />
          </parameters>
        </constructedValue>
      </default>
    </autoMethod>
  </autoService>
</autoGeneratedServices>

Startup Actions

  • The XML Configuration file has iocConfiguration/startupActions/startupAction elements for specifying any number of startup actions. Each startupAction element specifies a type that is an implementation of interface IoC.Configuration.OnApplicationStart.IStartupAction.

  • When the XML configuration file is loaded IoC.Configuration will call the method IoC.Configuration.OnApplicationStart.IStartupAction.Start() for each startup action specified in startupAction elements.

  • When the XML configuration file is disposed of (when IoC.Configuration.DiContainerBuilder.IContainerInfo is disposed of), IoC.Configuration.OnApplicationStart.IStartupAction.Stop() is called on each startup action.

  • Startup actions are integrated into dependency injection mechanism. Therefore, the constructor parameters of IoC.Configuration.OnApplicationStart.IStartupAction implementations specified in startupAction elements will be injected using the bindings specified in XML Configuration file or in modules referenced by the configuration file. Also, parameters and injectedProperties elements can used with startupActions to specify constructor parameter values or to inject properties.

  • IoC.Configuration waits for up to 15 seconds, to make sure that all startup actions are given enough time to properly stop (e.g., stop the threads if necessary).

    Note

    If all startup actions have true value of property IStartupAction.ActionExecutionCompleted, before 15 seconds passes, the wait time will be shorter.

Here is an example of startup action elements in configuration file:

<startupActions>
    <startupAction type="DynamicallyLoadedAssembly1.Implementations.StartupAction1"
                   assembly="dynamic1">
      <!--Use parameters element to specify constructor parameters if necessary.-->
      <!--<parameters></parameters>-->
      <!--Use injectedProperties element to inject properties into startup action if necessary.-->
      <!--<injectedProperties></injectedProperties>-->
    </startupAction>
    <startupAction type="DynamicallyLoadedAssembly1.Implementations.StartupAction2"
                   assembly="dynamic1"></startupAction>
</startupActions>

Here is the definition of interface IoC.Configuration.OnApplicationStart.IStartupAction

public interface IStartupAction
{
    /// <summary>
    /// If <c>true</c>, the action was successfully stopped.
    /// </summary>
    bool ActionExecutionCompleted { get; }

    /// <summary>
    /// Starts the action.
    /// </summary>
    void Start();

    /// <summary>
    ///  Stops the action.
    /// </summary>
    void Stop();
}

Plugins

XML Configuration file has elements to specify plugins. Plugins are extensions that allow specifying additional type bindings, plugin specific settings and some other functionality:

Adding a Plugin

To add a plugin do the following:

  1. Add a child element plugin to iocConfiguration/plugins and specify the plugin name using the name attribute. See the example below:

    Note

    All the types related to plugins should be in assemblies that are in a directory [plugins directoy][plugin name], where [plugins directoy] is the directory specified in attribute pluginsDirPath of element iocConfiguration/plugins and [plugin name] is the value of attribute name of element iocConfiguration/plugins/plugin.

    <plugins pluginsDirPath="K:\...\TestDlls\PluginDlls">
    
        <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->
    
        <!--A folder K:\...\TestDlls\PluginDlls\Plugin1 should exist.  -->
        <plugin name="Plugin1" />
        <plugin name="Plugin2" />
        <plugin name="Plugin3" enabled="false" />
    </plugins>
    
  2. Add a child element pluginSetup to iocConfiguration/pluginsSetup (iocConfiguration/pluginsSetup is next to iocConfiguration/startupActions element), and make sure to use the same value for plugin attribute as the value of attribute name in plugin element mentioned in step 1).

  • Here is an example of iocConfiguration/pluginsSetup/pluginSetup element with explanation of some elements in pluginSetup element.
  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
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
<pluginsSetup>
    <pluginSetup plugin="Plugin1">
        <!--The type in pluginImplementation should be non-abstract class
                  that implements IoC.Configuration.IPlugin and which has a public constructor-->
        <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1">
            <parameters>
                <int64 name="param1" value="25" />
            </parameters>
            <injectedProperties>
                <int64 name="Property2" value="35"/>
            </injectedProperties>
        </pluginImplementation>

        <settings>
            <int32 name="Int32Setting1" value="25" />
            <int64 name="Int64Setting1" value="38" />
            <string name="StringSetting1" value="String Value 1" />
        </settings>

        <webApi>
            <controllerAssemblies>
                <!--
                Specify assemblies with API controllers.
                The user of IoC.Configuration should add the assemblies to MVC using
                IMvcBuilder.AddApplicationPart(System.Reflection.Assembly)
                -->
                <controllerAssembly assembly="pluginassm1" />
                <controllerAssembly assembly="plugin1api" />
            </controllerAssemblies>
        </webApi>

        <dependencyInjection>
            <modules>
                <module type="ModulesForPlugin1.Ninject.NinjectModule1">
                    <parameters>
                        <int32 name="param1" value="101" />
                    </parameters>
                </module>
                <module type="ModulesForPlugin1.Autofac.AutofacModule1">
                    <parameters>
                        <int32 name="param1" value="102" />
                    </parameters>
                </module>
                <module type="ModulesForPlugin1.IoC.DiModule1">
                    <parameters>
                        <int32 name="param1" value="103" />
                    </parameters>
                </module>
            </modules>

            <services>
                <service type="TestPluginAssembly1.Interfaces.IDoor">
                    <implementation type="TestPluginAssembly1.Implementations.Door"
                                    scope="transient">
                        <parameters>
                            <int32 name="Color" value="3" />
                            <double name="Height" value="180" />
                        </parameters>
                    </implementation>
                </service>

                <service type="TestPluginAssembly1.Interfaces.IRoom">
                    <implementation type="TestPluginAssembly1.Implementations.Room"
                                    scope="transient">
                        <parameters>
                            <object name="door1" type="TestPluginAssembly1.Interfaces.IDoor"
                                    value="5,185.1" />
                            <injectedObject name="door2" type="TestPluginAssembly1.Interfaces.IDoor" />
                        </parameters>
                        <injectedProperties>
                            <object name="Door2" type="TestPluginAssembly1.Interfaces.IDoor"
                                    value="7,187.3" />
                        </injectedProperties>
                    </implementation>
                </service>
            </services>

            <autoGeneratedServices>
                <!--The scope for autoService implementations is always singleton -->
                <autoService interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
                    <autoMethod name="GetValidators"
                                returnType="System.Collections.Generic.IEnumerable[TestPluginAssembly1.Interfaces.IResourceAccessValidator]"
                                reuseValue="true" >
                        <methodSignature>
                            <string paramName="resourceName"/>
                        </methodSignature>
                        <if parameter1="public_pages">
                            <collection>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                            </collection>
                        </if>
                        <if parameter1="admin_pages">
                            <collection>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                            </collection>
                        </if>
                        <default>
                            <collection>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                            </collection>
                        </default>
                    </autoMethod>
                </autoService>
            </autoGeneratedServices>
        </dependencyInjection>
    </pluginSetup>
</pluginsSetup>

Element pluginImplementation

The element iocConfiguration/pluginsSetup/pluginSetup/pluginImplementation is used to specify an implementation of interface IoC.Configuration.IPlugin for the plugin. The easiest way to provide an implementation of IoC.Configuration.IPlugin is to extend the abstract class IoC.Configuration.PluginAbstr and to override the abstract methods IoC.Configuration.PluginAbstr.Initialize() and IoC.Configuration.PluginAbstr.Dispose(). PluginAbstr implements IoC.Configuration.IPlugin.

Note

Plugins are integrated into dependency injection mechanism. Therefore, the constructor parameters of IoC.Configuration.IPlugin implementations specified in pluginImplementation elements will be injected using the bindings specified in XML Configuration file or in modules referenced by the configuration file. Also, parameters and injectedProperties elements can used with pluginImplementation element to specify constructor parameters or property injection.

Here is an example of implementation of IoC.Configuration.IPlugin interface that is referenced in element iocConfiguration/pluginsSetup/pluginSetup/pluginImplementation in example above:

public class Plugin1 : IoC.Configuration.PluginAbstr
{
    private readonly List<SettingInfo> _requiredSettings;

    public Plugin1(long param1)
    {
        Property1 = param1;
        _requiredSettings = new List<SettingInfo>();
        _requiredSettings.Add(new SettingInfo("Int32Setting1", typeof(int)));
        _requiredSettings.Add(new SettingInfo("StringSetting1", typeof(string)));
    }

    public override IEnumerable<SettingInfo> RequiredSettings => _requiredSettings;

    public override void Dispose()
    {
        // Dispose resources
    }

    public override void Initialize()
    {
        // Do initialization here
    }

    public long Property1 { get; }
    public long Property2 { get; set; }
}
Getting Plugin Data at Runtime
  • To access an instance of IoC.Configuration.IPlugin for specific plugin, inject type IoC.Configuration.IPluginDataRepository (using constructor or property injection), and use the method IPluginData GetPluginData(string pluginName) in interface IoC.Configuration.IPluginDataRepository.

An example is demonstrated below:

public class AccessPluginDataExample
{
    public AccessPluginDataExample(IoC.Configuration.IPluginDataRepository pluginDataRepository)
    {
        var pluginData = pluginRepository.GetPluginData("Plugin1");
        Assert.AreEqual(35, pluginData.Property2);
        Assert.AreEqual(25,
            pluginData.Settings.GetSettingValueOrThrow<int>("Int32Setting1"));
    }
}

Element typeDefinition in plugin section

Element iocConfiguration/pluginsSetup/pluginSetup/typeDefinitions/typeDefinition can be used in plugin section to reference types by type alias, the same way this element is used in non-plugin section.

Refer to Using Types in Configuration File for more details on typeDefinition element.

Example of typeDefintion elements in pluginSetup element:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<pluginsSetup>
    <pluginSetup plugin="Plugin1">
        <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple" />
        <typeDefinitions>
            <!--Generic1_1_of_Interface1_Impl1 type definition overrides the
                definition in non-plugins section.-->
            <typeDefinition alias="ReadOnlyListOfGenericType"
                            type="System.Collections.Generic.IReadOnlyList" assembly="corlib">
                <genericTypeParameters>
                    <typeDefinition type="SharedServices.Implementations.Generic.Generic3_1" >
                        <genericTypeParameters>
                            <typeDefinition
                                type="SharedServices.Implementations.Interface1_Impl1" />
                        </genericTypeParameters>
                    </typeDefinition>
                </genericTypeParameters>
            </typeDefinition>
            <typeDefinition alias="IDoor" type="TestPluginAssembly1.Interfaces.IDoor" />
            <typeDefinition alias="Door" type="TestPluginAssembly1.Implementations.Door" />
            <typeDefinition alias="plugin1Module" type="ModulesForPlugin1.IoC.DiModule2" />
        </typeDefinitions>
    </pluginSetup>
<pluginsSetup>

Plugin Settings

An element iocConfiguration/pluginsSetup/pluginSetup/settings can be used to specify plugin specific settings. The format of plugin settings is similar to settings in general area (i.e., in element iocConfiguration/settings). For more details on settings in general refer to Settings.

<!--...-->
<pluginSetup plugin="Plugin1">
    <!--...-->
    <settings>
        <int32 name="Int32Setting1" value="25" />
        <int64 name="Int64Setting1" value="38" />
        <string name="StringSetting1" value="String Value 1" />
    </settings>
    <!--...-->
</pluginSetup>

Here is an example of how to access plugin setting values at runtime:

public class AccessPluginDataExample
{
    public AccessPluginDataExample(IoC.Configuration.IPluginDataRepository pluginDataRepository)
    {
        var pluginData = pluginRepository.GetPluginData("Plugin1");

        Assert.AreEqual(25,
                        pluginData.Settings.GetSettingValueOrThrow<int>("Int32Setting1"));
        Assert.AreEqual("String Value 1",
                        pluginData.Settings.GetSettingValueOrThrow<string>("StringSetting1"));
    }
}
  • If a setting is not found in plugin settings element iocConfiguration/pluginsSetup/pluginSetup/settings, IoC.Configuration will search for a setting in general settings area (i.e., in settings defined in element iocConfiguration/settings).
  • To specify required settings, implement the property IEnumerable<SettingInfo> RequiredSettings { get; } in interface IoC.Configuration.IPlugin, or override the virtual property with the same name in IoC.Configuration.PluginAbstr, if the plugin implementation is a subclass of IoC.Configuration.PluginAbstr class.

Plugin Modules

  • Plugin modules can be specified in module elements under element iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/modules.
  • The format of iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/modules is similar to the format of element iocConfiguration/dependencyInjection/modules, except that plugin modules are used to specify type bindings for plugin related types. See Modules for more details on iocConfiguration/dependencyInjection/modules element.

Plugin Type Bindings

Plugin related type binding can be specified either under element iocConfiguration/dependencyInjection/services to provide plugin related implementations for non plugin interfaces, or under element iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/services for cases when both the service and the implementation are plugin specific.

Note

If the plugin is disabled by setting the value of attribute enabled in element iocConfiguration/plugins/plugin for the specific plugin, the type bindings for the given plugin will be ignored.

Example 1: Plugin Specific Implementation for non Plugin Type

Here is an example of binding a non-plugin service SharedServices.Interfaces.IInterface5 to plugin specific type TestPluginAssembly1.Implementations.Interface5_Plugin1Impl.

<iocConfiguration>
    <!--...-->
    </dependencyInjection>
        <!--...-->
        <services>
            <service type="SharedServices.Interfaces.IInterface5" assembly="shared_services">
                <implementation type="SharedServices.Implementations.Interface5_Impl1"
                                assembly="shared_services"
                                scope="singleton" />
                <implementation type="TestPluginAssembly1.Implementations.Interface5_Plugin1Impl"
                                assembly="pluginassm1" scope="singleton" />
                <implementation type="TestPluginAssembly2.Implementations.Interface5_Plugin2Impl"
                                assembly="pluginassm2" scope="transient" />
                <implementation type="TestPluginAssembly3.Implementations.Interface5_Plugin3Impl"
                                assembly="pluginassm3" scope="transient" />
            </service>
            <!--...-->
        </services>
        <!--...-->
    </dependencyInjection>
</iocConfiguration>
Example 2: Plugin Specific Implementation for Plugin Type

Here is an example of binding a plugin service TestPluginAssembly1.Interfaces.IDoor to plugin specific type TestPluginAssembly1.Implementations.Door.

<iocConfiguration>
    <!--...-->
    <pluginsSetup>
        <pluginSetup plugin="Plugin1">
            <!--...-->
            <dependencyInjection>
                <services>
                    <service type="TestPluginAssembly1.Interfaces.IDoor"
                             assembly="pluginassm1">
                        <implementation type="TestPluginAssembly1.Implementations.Door"
                                        assembly="pluginassm1"
                                        scope="transient">
                            <parameters>
                                <int32 name="Color" value="3" />
                                <double name="Height" value="180" />
                            </parameters>
                        </implementation>
                    </service>
                    <!--...-->
                </services>
                <!--...-->
            <dependencyInjection>
        </pluginSetup>
        <!--...-->
    <pluginsSetup>
    <!--...-->
<iocConfiguration>

Plugin types in collection in non-plugin section

Plugin types can be used in value initializer elements for specifying items in collection element plugin as well as in non-plugin section.

Note

Refer to collection element for more details on collection element.

Note

Refer to Value Initialization Elements for more details on value intialization elements.

If value of plugin type is used in a collection item in non-plugin section, and the plugin is disabled by setting the value of attribute enabled in element iocConfiguration/plugins/plugin for the specific plugin, the item will not be included in a collection generated by IoC.Configuration.

Autogenerated Services

An interface with auto-generated implementations can be specified in element iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices. For more information on autogenerated services see Autogenerated Services.

Here is an example of autoGeneratedServices for a plugin. In this example, IoC.Configuration will generate an implementation of TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory and will configure a type binding, that ,apts the interface IResourceAccessValidatorFactory to auto-generated type.

 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
<autoGeneratedServices>
    <autoService interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
        <autoMethod name="GetValidators"
                    returnType="System.Collections.Generic.IEnumerable[TestPluginAssembly1.Interfaces.IResourceAccessValidator]"
                    reuseValue="true" >
            <methodSignature>
                <string paramName="resourceName"/>
            </methodSignature>

            <if parameter1="public_pages">
                <collection>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                </collection>
            </if>

            <if parameter1="admin_pages">
                <collection>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                </collection>
            </if>

            <default>
                <collection>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                </collection>
            </default>
        </autoMethod>
    </autoService>
</autoGeneratedServices>

The definition of interface IResourceAccessValidatorFactory is shown below

public interface IResourceAccessValidatorFactory
{
    IEnumerable<IResourceAccessValidator> GetValidators(string resourceName);
}

Additional Services Provided by IoC.Configuration

In addition to registering types specified in XML configuration file and module classes, IoC.Configuration registers bindings for number of other interfaces. Instances of these interfaces can be accessed using constructor or property injection.

Here are some of the interfaces mentioned above:

  • IoC.Configuration.DiContainer.IDiContainer: The IoC container.
  • IoC.Configuration.ConfigurationFile.IConfiguration: Stores the structure of XML configuration file.
  • ISettings: Stores the settings specified in element iocConfiguration/settings (see Settings for more details on settings).
  • IoC.Configurati.IPluginDataRepository and IoC.Configuration.ConfigurationFile.IPluginsSetup: Provides access to registered plugins data (see Plugins for more details on plugins).

Troubleshooting Configuration File Errors

IoC.Configuration logs helpfull tips on source of configuration file load errors.

Note

Refer to Loading IoC Configuration for details on how to setup the logger.

Example of error logs is shown below:

Fatal:
Exception:Error in element 'settings':
Required setting 'Int32Setting1' should be of type 'System.Int32'. Actual type is 'System.String'. The setting is in plugin settings for plugin 'Plugin1'. To fix the issue, either modify the implementation of method 'RequiredSettings' in class 'TestPluginAssembly1.Implementations.Plugin1', or add the setting.
Element location in configuration file:
<iocConfiguration>
    <pluginsSetup>
            <pluginSetup plugin="Plugin1">
                    <settings>
                            <int64 name="Int64Setting1" value="38"/>
                            <string name="StringSetting1" value="String Value 1"/>
                            <string name="Int32Setting1" value="some text"/> <--- Element 'string' is the 3-th child element of element 'settings'.

   at IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfiguration.ValidateRequiredSettings(ISettings settings, ISettingsRequestor settingsRequestor)
   at IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfiguration.ValidateRequiredSettings(IDiContainer diContainer)
   at IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfiguration.OnContainerStarted()
   at IoC.Configuration.DiContainerBuilder.DiContainerBuilderConfiguration.StartContainer()

Loading IoC Configuration

  • The dependency injection configuration can be loaded either from modules (see Type Binding In Modules for more details on modules), or from XML Configuration file, in which both type binding as well as module classes can be specified (see XML Configuration File for more details on XML Configuration file).

  • Before the configuration is loaded, an instance of OROptimizer.Diagnostics.Log.ILogHelperContext should be registered, using OROptimizer.Diagnostics.Log.LogHelper.RegisterContext(ILogHelperContext). An implementation of ILogHelperContext for log4net, OROptimizer.Diagnostics.Log.Log4NetHelperContext, can be found in Nuget package OROptimizer.Shared (referenced by IoC.Configuration library).

    Here is an example of registering the logger:

    if (!OROptimizer.Diagnostics.Log.LogHelper.IsContextInitialized)
        OROptimizer.Diagnostics.Log.LogHelper.RegisterContext(
            new Log4NetHelperContext("MyApp.log4net.config"));
    

Loading from XML Configuration File

An example of XML configuration file can be found at IoCConfiguration_Overview.xml. This file is used in test project IoC.Configuration.Tests.

-The XML Configuration file is validated against XML schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd (see XML Configuration File Schema). -A template XML Configuration file IoC.Configuration.Template.xml can be found in folder IoC.Configuration.Content, where the Nuget package IoC.Configuration is installed (see XML Configuration Template).

To load the IoC configuration from XML configuration file use method IoC.Configuration.DiContainerBuilder.DiContainerBuilder.StartFileBasedDi() as shown below.

 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using OROptimizer.Xml; // add this using statement to be able to use XmlDocument extensions (i.e., e.XmlDocument.SelectElements("/iocConfiguration/diManagers"), etc.)
// ...

using (var containerInfo =
        new DiContainerBuilder.DiContainerBuilder()
        .StartFileBasedDi(
            new FileBasedConfigurationParameters(
                new FileBasedConfigurationFileContentsProvider(
                    Path.Combine(Helpers.TestsEntryAssemblyFolder, "IoCConfiguration_Overview.xml")),
                // Provide the entry assembly folder. Normally this is the folder,
                // where the executable file is. However for test projects this might not
                // be the case. This folder will be used in assembly resolution.
                Helpers.TestsEntryAssemblyFolder,
                new LoadedAssembliesForTests())
            {
                AdditionalReferencedAssemblies = new string[]
                {
                    // List additional assemblies that should be added to dynamically generated assembly as references
                    Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"),
                    Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly2.dll")
                },
                // Set the value of AttributeValueTransformers to list of
                // IoC.Configuration.AttributeValuesProvider.IAttributeValueTransformer instances
                // to change some xml attribute values when the xml configuration is loaded,
                // before the configuration is parsed.
                // Good example of implementation of IoC.Configuration.AttributeValuesProvider.IAttributeValueTransformer
                // is IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.
                AttributeValueTransformers = new IAttributeValueTransformer []
                {
                    new FileFolderPathAttributeValueTransformer()
                },
                ConfigurationFileXmlDocumentLoaded = (sender, e) =>
                {
                    // Replace some elements in e.XmlDocument if needed,
                    // before the configuration is loaded.
                    // For example, we can replace the value of attribute 'activeDiManagerName' in element
                    // iocConfiguration.diManagers to use a different DI manager (say
                    // switch from Autofac to Ninject).
                    Helpers.EnsureConfigurationDirectoryExistsOrThrow(e.XmlDocument.SelectElement("/iocConfiguration/appDataDir").GetAttribute("path"));
                    e.XmlDocument.SelectElements("/iocConfiguration/diManagers")
                        .First()
                        .SetAttributeValue("activeDiManagerName", "Autofac");
                }
            }, out _)
        // Note, most of the time we will need to call method WithoutPresetDiContainer().
        // However, in some cases, we might need to create an instance of IoC.Configuration.DiContainer.IDiContainer,
        // and call the method WithDiContainer(IoC.Configuration.DiContainer.IDiContainer diContainer) instead.
        // This might be necessary when using the IoC.Configuration to configure dependency injection in
        // ASP.NET Core projects.
        // An example implementation of IDIContainer is IoC.Configuration.Autofac.AutofacDiContainer in
        // Nuget package IoC.Configuration.Autofac.
        .WithoutPresetDiContainer()

        // Note, native and IoC.Configuration modules can be specified in XML configuration file, in
        // iocConfiguration/dependencyInjection/modules/module elements.
        // However, if necessary, AddAdditionalDiModules() and AddNativeModules() can be used to load additional
        // IoC.Configuration modules (instances of IoC.Configuration.DiContainer.IDiModule), as well
        // as native (e.g, Ninject or Autofac) modules.
        // Also, AddAdditionalDiModules() and AddNativeModules() can be called multiple times in any order.
        .AddAdditionalDiModules(new TestDiModule())
        .AddNativeModules(CreateModule<object>("Modules.Autofac.AutofacModule1",
            new ParameterInfo[] { new ParameterInfo(typeof(int), 5) }))
        .RegisterModules()
        .Start())
{
    var diContainer = containerInfo.DiContainer;

    // Once the configuration is loaded, resolve types using IoC.Configuration.DiContainer.IDiContainer
    // Note, interface IoC.Configuration.DiContainerBuilder.IContainerInfo extends System.IDisposable,
    // and should be disposed, to make sure all the resources are properly disposed of.
    var resolvedInstance = containerInfo.DiContainer.Resolve<SharedServices.Interfaces.IInterface7>();
}
  • Once the configuration is loaded into containerInfo variable of type IoC.Configuration.DiContainerBuilder.IContainerInfo, resolve types using property DiContainer in IoC.Configuration.DiContainerBuilder.IContainerInfo (the property is of type IoC.Configuration.DiContainer.IDiContainer).

  • Interface IoC.Configuration.DiContainerBuilder.IContainerInfo extends System.IDisposable.

  • Native and IoC.Configuration modules can be specified in XML configuration file, in iocConfiguration/dependencyInjection/modules/module elements. However, if necessary, use the following methods in IoC.Configuration.DiContainerBuilder.FileBased.IFileBasedDiModulesConfigurator to load additional IoC.Configuration modules (instances of IoC.Configuration.DiContainer.IDiModule), as well as native (e.g, Ninject or Autofac) modules:
    • IFileBasedDiModulesConfigurator.AddAdditionalDiModules(params IDiModule[] diModules)
    • IFileBasedDiModulesConfigurator.AddNativeModules(params object[] nativeModules)

    Note

    These methods can be called multiple times in any order. In other words, we can add some IoC.Configuration modules using AddAdditionalDiModules, then some native modules using AddNativeModules(), then some more IoC.Configuration modules using AddAdditionalDiModules.

Modifying XML Configuration at Runtime

The XML Configuration file can be modified at runtime by passing a delegate for parameter configurationFileXmlDocumentLoaded in method IoC.Configuration.DiContainerBuilder.StartFileBasedDi(IConfigurationFileContentsProvider configurationFileContentsProvider, string entryAssemblyFolder, ConfigurationFileXmlDocumentLoadedEventHandler configurationFileXmlDocumentLoaded = null).

This method loads the configuration file into an instance of System.Xml.XmlDocument object, and executes the delegate passed in parameter configurationFileXmlDocumentLoaded.

By the time the delegate is executed, System.Xml.XmlDocument object is not yet validated against the XML schema file IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd (this is done after the delegate is executed). Therefore, the changes to System.Xml.XmlDocument object should be done in such a way that the XML document is still valid against this schema file.

Example of modifying the XML document at runtime to replace the value of attribute activeDiManagerName in element /iocConfiguration/diManagers with Autofac is shown below (this is copied from the C# code above).

new DiContainerBuilder.DiContainerBuilder()
       .StartFileBasedDi(
            // Other parameters...
            (sender, e) =>
            {
                e.XmlDocument.SelectElements("/iocConfiguration/diManagers").First()
                     .SetAttributeValue("activeDiManagerName", "Autofac");
            })

Loading from Modules

To load the IoC configuration from XML configuration file use method IoC.Configuration.DiContainerBuilder.DiContainerBuilder.StartCodeBasedDi() as shown below.

 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
   var assemblyProbingPaths = new[]
   {
       @"K:\...\TestDlls\ThirdPartyLibs",
       @"K:\...\TestDlls\ContainerImplementations\Autofac"
   };

   using (var containerInfo = new DiContainerBuilder.DiContainerBuilder()

           // Class IoC.Configuration.DiContainerBuilder.DiContainerBuilder has two overloaded methods StartCodeBasedDi(...)
           // DiContainerBuilder.StartCodeBasedDi(IoC.Configuration.DiContainer.IDiManager diManager,...) and
           // DiContainerBuilder.StartCodeBasedDi(string diManagerClassFullName, string diManagerClassAssemblyFilePath,...).
           // if the project references the library with implementation of IoC.Configuration.DiContainer.IDiManager,
           // the first one can be used. Otherwise the second overloaded method can be used, in which case reflection will be used to
           // create an instance of IoC.Configuration.DiContainer.IDiManager.
           .StartCodeBasedDi("IoC.Configuration.Autofac.meake cleanAutofacDiManager",
                          @"K:\...\TestDlls\ContainerImplementations\Autofac\IoC.Configuration.Autofac.dll",
                          new ParameterInfo[0], Helpers.TestsEntryAssemblyFolder, assemblyProbingPaths)

           // Note, most of the time we will need to call method WithoutPresetDiContainer().
           // However, in some cases, we might need to create an instance of IoC.Configuration.DiContainer.IDiContainer,
           // and call the method WithDiContainer(IoC.Configuration.DiContainer.IDiContainer diContainer) instead.
           // This might be necessary when using the IoC.Configuration to configure dependency injection in
           // ASP.NET Core projects.
           // An example implementation of IDIContainer is IoC.Configuration.Autofac.AutofacDiContainer in
           // Nuget package IoC.Configuration.Autofac.
           .WithoutPresetDiContainer()

           // The methods AddDiModules(params IDiModule[] diModules),
           // AddNativeModules(params object[] nativeModules), and
           // AddNativeModules(string nativeModuleClassFullName, string nativeModuleClassAssemblyFilePath, ...)
           // are used to load IoC.Configuration modules (instances of IoC.Configuration.DiContainer.IDiModule), as well
           // as native (e.g, Ninject or Autofac) modules.
           // Also, these three methods can be called multiple times in any order.
           .AddDiModules(new TestDiModule())
           .AddNativeModule("Modules.Autofac.AutofacModule1",
               @"K:\...\TestDlls\DynamicallyLoadedDlls\TestProjects.Modules.dll",
               new ParameterInfo[] { new ParameterInfo(typeof(int), 5) })

           .RegisterModules()
           .Start())
   {
       var diContainer = containerInfo.DiContainer;

       // Once the configuration is loaded, resolve types using IoC.Configuration.DiContainer.IDiContainer
       // Note, interface IoC.Configuration.DiContainerBuilder.IContainerInfo extends System.IDisposable,
       // and should be disposed, to make sure all the resources are properly disposed of.
       var resolvedInstance = containerInfo.DiContainer.Resolve<IInterface2>();
   }
  • Once the configuration is loaded into containerInfo variable of type IoC.Configuration.DiContainerBuilder.IContainerInfo, resolve types using property DiContainer in IoC.Configuration.DiContainerBuilder.IContainerInfo (the property is of type IoC.Configuration.DiContainer.IDiContainer).

  • Interface IoC.Configuration.DiContainerBuilder.IContainerInfo extends System.IDisposable.

  • Use one of the following overloaded methods in class IoC.Configuration.DiContainerBuilder.DiContainerBuilder to specify an instance of IoC.Configuration.DiContainer.IDiManager, that handles the type resolutions and translates the bindings in IoC.Configuration modules into native container bindings (e.g., Autofac and Ninject bindings).
    • DiContainerBuilder.StartCodeBasedDi(IDiManager diManager, string entryAssemblyFolder, params string[] assemblyProbingPaths)
    • DiContainerBuilder.StartCodeBasedDi(string diManagerClassFullName, string diManagerClassAssemblyFilePath, ParameterInfo[] diManagerConstructorParameters, string entryAssemblyFolder, params string[] assemblyProbingPaths). This method is handy if the project does not reference the assembly with implementation of IoC.Configuration.DiContainer.IDiManager. IoC.Configuration will use refelction to load the type.

    Note

    Currently two implementations of IoC.Configuration.DiContainer.IDiManager are available: IoC.Configuration.Autofac.AutofacDiManager and IoC.Configuration.Ninject.NinjectDiManager. These implementations are available in Nuget packages IoC.Configuration.Autofac and IoC.Configuration.Ninject

  • The following methods in interface IoC.Configuration.DiContainerBuilder.CodeBased.ICodeBasedDiModulesConfigurator can be used to load IoC.Configuration modules IoC.Configuration modules (instances of IoC.Configuration.DiContainer.IDiModule), as well as native (e.g, Ninject or Autofac) modules:
    • ICodeBasedDiModulesConfigurator.AddDiModules(params IoC.Configuration.DiContainer.IDiModule[] diModules)
    • ICodeBasedDiModulesConfigurator.AddNativeModules(params object[] nativeModules)
    • ICodeBasedDiModulesConfigurator.AddNativeModule(string nativeModuleClassFullName, string nativeModuleClassAssemblyFilePath, ParameterInfo[] nativeModuleConstructorParameters)

    Note

    These methods can be called multiple times in any order.

Resolving Types

To resolve the types, we first need to load the configuration into an instance of IoC.Configuration.DiContainerBuilder.IContainerInfo.

Refer to sections Loading from XML Configuration File and Loading from Modules for more details.

Here is an example of loading from XML Configuration file:

 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using OROptimizer.Xml; // add this using statement to be able to use XmlDocument extensions (i.e., e.XmlDocument.SelectElements("/iocConfiguration/diManagers"), etc.)
// ...

using (var containerInfo =
        new DiContainerBuilder.DiContainerBuilder()
        .StartFileBasedDi(
            new FileBasedConfigurationParameters(
                new FileBasedConfigurationFileContentsProvider(
                    Path.Combine(Helpers.TestsEntryAssemblyFolder, "IoCConfiguration_Overview.xml")),
                // Provide the entry assembly folder. Normally this is the folder,
                // where the executable file is. However for test projects this might not
                // be the case. This folder will be used in assembly resolution.
                Helpers.TestsEntryAssemblyFolder,
                new LoadedAssembliesForTests())
            {
                AdditionalReferencedAssemblies = new string[]
                {
                    // List additional assemblies that should be added to dynamically generated assembly as references
                    Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"),
                    Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly2.dll")
                },
                // Set the value of AttributeValueTransformers to list of
                // IoC.Configuration.AttributeValuesProvider.IAttributeValueTransformer instances
                // to change some xml attribute values when the xml configuration is loaded,
                // before the configuration is parsed.
                // Good example of implementation of IoC.Configuration.AttributeValuesProvider.IAttributeValueTransformer
                // is IoC.Configuration.Tests.FileFolderPathAttributeValueTransformer.
                AttributeValueTransformers = new IAttributeValueTransformer []
                {
                    new FileFolderPathAttributeValueTransformer()
                },
                ConfigurationFileXmlDocumentLoaded = (sender, e) =>
                {
                    // Replace some elements in e.XmlDocument if needed,
                    // before the configuration is loaded.
                    // For example, we can replace the value of attribute 'activeDiManagerName' in element
                    // iocConfiguration.diManagers to use a different DI manager (say
                    // switch from Autofac to Ninject).
                    Helpers.EnsureConfigurationDirectoryExistsOrThrow(e.XmlDocument.SelectElement("/iocConfiguration/appDataDir").GetAttribute("path"));
                    e.XmlDocument.SelectElements("/iocConfiguration/diManagers")
                        .First()
                        .SetAttributeValue("activeDiManagerName", "Autofac");
                }
            }, out _)
        // Note, most of the time we will need to call method WithoutPresetDiContainer().
        // However, in some cases, we might need to create an instance of IoC.Configuration.DiContainer.IDiContainer,
        // and call the method WithDiContainer(IoC.Configuration.DiContainer.IDiContainer diContainer) instead.
        // This might be necessary when using the IoC.Configuration to configure dependency injection in
        // ASP.NET Core projects.
        // An example implementation of IDIContainer is IoC.Configuration.Autofac.AutofacDiContainer in
        // Nuget package IoC.Configuration.Autofac.
        .WithoutPresetDiContainer()

        // Note, native and IoC.Configuration modules can be specified in XML configuration file, in
        // iocConfiguration/dependencyInjection/modules/module elements.
        // However, if necessary, AddAdditionalDiModules() and AddNativeModules() can be used to load additional
        // IoC.Configuration modules (instances of IoC.Configuration.DiContainer.IDiModule), as well
        // as native (e.g, Ninject or Autofac) modules.
        // Also, AddAdditionalDiModules() and AddNativeModules() can be called multiple times in any order.
        .AddAdditionalDiModules(new TestDiModule())
        .AddNativeModules(CreateModule<object>("Modules.Autofac.AutofacModule1",
            new ParameterInfo[] { new ParameterInfo(typeof(int), 5) }))
        .RegisterModules()
        .Start())
{
    var diContainer = containerInfo.DiContainer;

    // Once the configuration is loaded, resolve types using IoC.Configuration.DiContainer.IDiContainer
    // Note, interface IoC.Configuration.DiContainerBuilder.IContainerInfo extends System.IDisposable,
    // and should be disposed, to make sure all the resources are properly disposed of.
    var resolvedInstance = containerInfo.DiContainer.Resolve<SharedServices.Interfaces.IInterface7>();
}

Once the IoC is loaded into IoC.Configuration.DiContainerBuilder.IContainerInfo, use methods in IoC.Configuration.DiContainerBuilder.IContainerInfo.DiContainer to resolve types.

Examples of resolving types:

// diContainer is created from XML configuration file or modules.
IoC.Configuration.DiContainerBuilder.IContainerInfo.DiContainer diContainer;

var instance1 = diContainer.Resolve(typeof(IInterface3));
var instance2 = diContainer.Resolve<IInterface3>();

using (var lifeTimeScope = diContainer.StartLifeTimeScope())
{
    var instance3 = diContainer.Resolve<IInterface1>(lifeTimeScope);
    var instance4 = diContainer.Resolve(typeof(IInterface3), lifeTimeScope);
}

Example of injecting a type into a constructor

public class TestTypeResolution
{
    private IInterface3 _instanceOfInterface3;

    // An instance of IInterface3 will be injected into constructor of TestTypeResolution
    // based on binding specified for type IInterface3 in XML configuration file or in IoC.Configuration
    // or native modules.
    public TestTypeResolution(IInterface3 instanceOfInterface3)
    {
        _instanceOfInterface3 = instanceOfInterface3;
    }
}

When the type is re-solved, the bindings specified in configuration file (see XML Configuration File) or in module classes (see Type Binding In Modules) are used to recursively inject constructor parameters, or to set the property values of resolved types (if property injection is specified in configuration file or in modules).

Resolution Scopes

Resolution scope determines if the same object or different objects will be returned by the container on subsequent requests of type.

IoC.Configuration supports three types of resolution scopes: Singleton, ScopeLifetime, and Transient scopes.

Scope: Singleton

Singleton scope results in type being resolved to the same instance on subsequent requests.

Here is an example of specifying Singleton resolution scope in method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations() (see Type Bindings in IoC.Configuration Modules):

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        Bind<SharedServices.Interfaces.IInterface9>()
        .To<SharedServices.Implementations.Interface9_Impl1>()
        .SetResolutionScope(DiResolutionScope.Singleton);
    }
}

Here is an example of specifying Singleton resolution scope in XML configuration file (see Service Bindings):

<service type="SharedServices.Interfaces.IInterface9" assembly="shared_services">
    <implementation type="SharedServices.Implementations.Interface9_Impl1"
                                assembly="shared_services"
                                scope="singleton" />
</service>

Here is an example of resolving types bound with Singleton scope resolution

private void SingletonScopeResolutionExample(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    var service1 = diContainer.Resolve<IInterface9>();
    var service2 = diContainer.Resolve<IInterface9>();
    Assert.AreSame(service1, service2);
}

Scope: Transient

Transient scope results in type being resolved to a newly created instance on each requests.

Here is an example of specifying Transient resolution scope in method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations() (see Type Bindings in IoC.Configuration Modules):

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        Bind<DynamicallyLoadedAssembly1.Interfaces.IInterface2>()
        .To<SharedServices.DynamicallyLoadedAssembly1.Implementations.Interface2_Impl1>()
        .SetResolutionScope(DiResolutionScope.Transient);
    }
}

Here is an example of specifying Transient resolution scope in XML configuration file (see Service Bindings):

<service type="DynamicallyLoadedAssembly1.Interfaces.IInterface2"
            assembly="dynamic1">
    <implementation type="DynamicallyLoadedAssembly1.Implementations.Interface2_Impl1"
                    assembly="dynamic1"
                    scope="transient">
    </implementation>
</service>

Here is an example of resolving types bound with Transient scope resolution

private void TransientScopeResolutionExample(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    Type typeInterface2 = Helpers.GetType("DynamicallyLoadedAssembly1.Interfaces.IInterface2");

    var service1 = diContainer.Resolve(typeInterface2);
    var service2 = diContainer.Resolve(typeInterface2);
    Assert.AreNotSame(service1, service2);
}

Scope: ScopeLifetime

ScopeLifetime scope results in type being resolved to the same instance on subsequent requests, if the same instance of IoC.Configuration.DiContainer.ILifeTimeScope is used as a parameter to method diContainer.Resolve(Type typeToResolve, ILifeTimeScope lifetimeScope).

Note

If DiResolutionScope.ScopeLifetime is not used when specifying the binding for the type, the value passed for ILifeTimeScope parameter in diContainer.Resolve(Type typeToResolve, ILifeTimeScope lifetimeScope) does not matter, and the type will be resolved with resolution scope used in type binding (e.g., Singleton, Transient).

Here is an example of specifying ScopeLifetime resolution scope in method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations() (see Type Bindings in IoC.Configuration Modules):

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {
        Bind<DynamicallyLoadedAssembly1.Interfaces.IInterface3>()
        .To<DynamicallyLoadedAssembly1.Implementations.Interface3_Impl1>()
        .SetResolutionScope(DiResolutionScope.ScopeLifetime);
    }
}

Here is an example of specifying ScopeLifetime resolution scope in XML configuration file (see Service Bindings):

<service type="DynamicallyLoadedAssembly1.Interfaces.IInterface3" assembly="dynamic1">
    <implementation type="DynamicallyLoadedAssembly1.Implementations.Interface3_Impl1"
                                assembly="dynamic1"
                                scope="scopeLifetime">
    </implementation>
</service>

Here is an example of resolving types bound with ScopeLifetime scope resolution:

private void LifetimeScopeResolutionExample(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    Type typeInterface3 = Helpers.GetType(
                        "DynamicallyLoadedAssembly1.Interfaces.IInterface3");

    // Same objects are created in default lifetime scope.
    var service1InMainScope = diContainer.Resolve(typeInterface3);
    var service2InMainScope = diContainer.Resolve(typeInterface3);

    Assert.AreSame(service1InMainScope, service2InMainScope);

    using (var lifeTimeScope = diContainer.StartLifeTimeScope())
    {
        // IDiContainer.Resolve(Type, ILifetimeScope) returns
        // the same object for the same scope lifeTimeScope.
        var service1InScope1 = diContainer.Resolve(typeInterface3, lifeTimeScope);
        var service2InScope1 = diContainer.Resolve(typeInterface3, lifeTimeScope);

        Assert.AreSame(service1InScope1, service2InScope1);

        // However, the objects are different from the ones created in main
        // lifetime scope.
        Assert.AreNotSame(service1InScope1, service1InMainScope);
    }
}

Multiple Bindings

If we know that only one binding for the type was specified in configuration file (see XML Configuration File) or in modules (see Type Binding In Modules), we can resolve the type by specifying the type as a parameter to method IoC.Configuration.DiContainer.IDiContainer.Resove(Type), as shown below:

private void ResolvingATypeWithSingleBinding(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    Type typeInterface2 = Helpers.GetType("DynamicallyLoadedAssembly1.Interfaces.IInterface2");

    var service1 = diContainer.Resolve(typeInterface2);
    var service2 = diContainer.Resolve(typeInterface2);
    Assert.AreNotSame(service1, service2);
}

However, multiple bindings might be specified for the same type as well. Below are examples of specifying multiple bindings for the same type in configuration file, and in overridden method in method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations().

Example of multiple bindings for type in XML configuration file:

<service type="SharedServices.Interfaces.IInterface5" assembly="shared_services">
    <implementation type="SharedServices.Implementations.Interface5_Impl1"
                            assembly="shared_services"
                            scope="singleton" />
    <implementation type="TestPluginAssembly1.Implementations.Interface5_Plugin1Impl"
                            assembly="pluginassm1" scope="singleton" />
    <implementation type="TestPluginAssembly2.Implementations.Interface5_Plugin2Impl"
                            assembly="pluginassm2" scope="transient" />
</service>

Example of multiple bindings for type in overridden method in method IoC.Configuration.DiContainer.ModuleAbstr.AddServiceRegistrations():

public class TestDiModule : IoC.Configuration.DiContainer.ModuleAbstr
{
    protected override void AddServiceRegistrations()
    {

        Bind<SharedServices.Interfaces.IInterface5>()
                    .To<SharedServices.Implementations.Interface5_Impl1>()
                    .SetResolutionScope(DiResolutionScope.Singleton);

        Bind<SharedServices.Interfaces.IInterface5>()
                    .To<TestPluginAssembly1.Implementations.Interface5_Plugin1Impl>()
                    .SetResolutionScope(DiResolutionScope.Singleton);

        Bind<SharedServices.Interfaces.IInterface5>()
                    .To<TestPluginAssembly2.Implementations.Interface5_Plugin2Impl>()
                    .SetResolutionScope(DiResolutionScope.Transient);
    }
}

To resolve types that are bound to multiple types, resolve type System.Collections.Generic.IEnumerable<TService>.

Note

We still can resolve to a single type, rather than to a collection. However, not all implementations support this resolution, when multiple bindings exist. For example, Autofac implementation will resolve the type to the last binding, while Ninject implementation will throw an exception.

private void ResolvingATypeWithMultipleBindings(IoC.Configuration.DiContainer.IDiContainer diContainer)
{
    var resolvedInstances = diContainer.Resolve<IEnumerable<SharedServices.Interfaces.IInterface5>>()
                                       .ToList();

    Assert.AreEqual(3, resolvedInstances.Count);

    var typeOfInterface5 = typeof(IInterface5);
    Assert.IsInstanceOfType(resolvedInstances[0], typeOfInterface5);
    Assert.IsInstanceOfType(resolvedInstances[1], typeOfInterface5);
    Assert.IsInstanceOfType(resolvedInstances[2], typeOfInterface5);
}

Application Integration

ASP.NET Core

IoC.Configuration can be used with ASP.NET Core to replace the dependency injection container that ASP.NET Core uses. This includes also re-solving ASP.NET Core controllers.

Follow these steps to integrate IoC.Configuration with ASP.NET Core.

  1. If necessary, use an element iocConfiguration/webApi (or iocConfiguration/pluginsSetup/pluginsSetup/webApi for configuring controllers for plugins) to list the assemblies that contain ASP.NET Core controllers.

    The IoC.Configuration user will have to iterate this assemblies and register them with ASP.NET Core, as will be shown in code in Step 3 below.

    Note

    Element webApi is optional, and is only needed if we want to use IoC.Configuration to register controllers specified in a different assembly.

    Here is an example of webApi element with an assembly with ASP.NET Core controllers:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
        <webApi>
            <controllerAssemblies>
                <!--
                Specify assemblies with API controllers.
                The user of IoC.Configuration should add the assemblies to MVC using
                IMvcBuilder.AddApplicationPart(System.Reflection.Assembly)
                -->
                <controllerAssembly assembly="dynamic1"></controllerAssembly>
            </controllerAssemblies>
        </webApi>
    
  2. If any assemblies with ASP.NET Core controllers were specified in Step 1, register bindings for controllers in these assemblies in dependency injection elements iocConfiguration/dependencyInjection/ or iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/.

Here is an exert from the configuration file demonstrating Steps 1 and 2.

  • Element webApi on line 9 lists an assembly with an alias smart_xml_docs as an assembly with ASP.NET Core controllers (see Assemblies and Probing Paths on how to register assemblies).
  • Element selfBoundService on line 17 specifies a binding for an ASP.NET Core controller WebFileSystemApi.SmartXmlDocs.Controllers.SmartXmlTestController in assembly with alias smart_xml_docs.
 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
    <pluginsSetup>
        <pluginSetup plugin="SmartXmlDocs">
            <pluginImplementation
                type="WebFileSystemApi.SmartXmlDocs.SmartXmlDocsPlugin"
                assembly="smart_xml_docs">
            </pluginImplementation>
            <settings>
            </settings>
            <webApi>
                <controllerAssemblies>
                    <controllerAssembly assembly="smart_xml_docs"/>
                </controllerAssemblies>
            </webApi>
            <dependencyInjection>
                <modules />
                <services>
                    <selfBoundService
                        type="WebFileSystemApi.SmartXmlDocs.Controllers.SmartXmlTestController"
                        assembly="smart_xml_docs" scope="transient" >
                    </selfBoundService>
                </services>
                <autoGeneratedServices>
                </autoGeneratedServices>
            </dependencyInjection>
        </pluginSetup>
    </pluginsSetup>

Here is the code for controller class WebFileSystemApi.SmartXmlDocs.Controllers.SmartXmlTestController:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
using Microsoft.AspNetCore.Mvc;
namespace WebFileSystemApi.SmartXmlDocs.Controllers
{
    [Route("[controller]/[action]")]
    public class SmartXmlTestController : Controller
    {
        [HttpGet("{smartXmlFileId:long}")]
        public string SmartXmlDoc(long smartXmlFileId)
        {
            return $"Smart XML File Id is {smartXmlFileId}";
        }
    }
}
  1. Finally register IoC.Configuration with ASP.NET Core by using method public IServiceProvider ConfigureServices(IServiceCollection services) in Startup class as shown below. There are detailed code comments in the example below, so no farther explanations are provided.

    Note

    Integration with ASP.NET Core is currently supported for IoC.Configuration.Autofac. Currently, the ASP.NET Core project will need to reference the Nuget packages Autofac, IoC.Configuration, and IoC.Configuration.Autofac. In future this might be improved to support other containers as well (such as Ninject), and to avoid referencing these packages in the project.

 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
private static IContainerInfo _containerInfo;

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Do some ASP.NET Core configuration
    var mvcBuilder = services.AddMvc()
        .AddMvcOptions(options =>
        {
            // ...
        })
        .AddJsonOptions(options =>
        {
            // ...
        })
        .AddControllersAsServices();

    var rootDirectory = AppDomain.CurrentDomain.BaseDirectory;

    // Load IoC.Configuration into iocContainerBuilder
    var iocContainerBuilder =
        new DiContainerBuilder()
            .StartFileBasedDi(
            new FileBasedConfigurationParameters(
            new FileBasedConfigurationFileContentsProvider(Path.Combine(rootDirectory, "WebFileSystem.IoC.Configuration.xml")),
                rootDirectory, new AllLoadedAssemblies())
            {
                ConfigurationFileXmlDocumentLoaded = (sender, e) =>
                {
                    // Do XML file transformations here
                }
            }, out var loadedConfiguration);

    // Register controller assemblies in webApi elements in IoC.Configuration file
    // with ASP.NET Core.
    Action<IoC.Configuration.ConfigurationFile.IWebApi> addControllersFromConfiguration =
        (webApi) =>
        {
            if (webApi == null || webApi.ControllerAssemblies == null)
                return;

            foreach (var controllerAssembly in webApi.ControllerAssemblies.Assemblies)
            {
                if (controllerAssembly.LoadedAssembly != null)
                    mvcBuilder.AddApplicationPart(controllerAssembly.LoadedAssembly);
            }
        };

    // Register controller assemblies in iocConfiguration/webApi element.
    addControllersFromConfiguration(loadedConfiguration.WebApi);

    // Now register controller assemblies in webApi elements under
    // iocConfiguration/pluginsSetup/pluginSetup elements.
    foreach (var pluginSetup in loadedConfiguration.PluginsSetup.AllPluginSetups)
    {
        if (pluginSetup.Enabled)
            addControllersFromConfiguration(pluginSetup.WebApi);
    }

    // Build the Autofac container builder and start the IoC.Configuration.
    var autofacContainerBuilder = new ContainerBuilder();

    // Register ASP.NET Core services with Autofac, however skip
    // the services, the full name of which starts with "WebFileSystemApi".
    // Registering bindings of non-Microsoft services will be done in
    // IoC.Configuration file.
    autofacContainerBuilder.Populate(
        services.Where(x =>
            !x.ServiceType.FullName.StartsWith("WebFileSystemApi", StringComparison.Ordinal)));

    // Since we provide an instance of
    // IoC.Configuration.Autofac.AutofacDiContainer,
    // IoC.Configuration.Autofac will not create and build instance of
    // Autofac.ContainerBuilder.
    // In this case, we need to call iocContainerStarter.Start() only after
    // we call autofacContainerBuilder.Build() below.
    var iocContainerStarter = iocContainerBuilder
        .WithDiContainer(new AutofacDiContainer(autofacContainerBuilder))
        .RegisterModules();

    var container = autofacContainerBuilder.Build();
    _containerInfo = iocContainerStarter.Start();

    return new AutofacServiceProvider(container);
}
1
2
3
4
5
    // Make sure OnShutdown() is called on ASP.NET Core shutdown, to dispose of _containerInfo.
    private void OnShutdown()
    {
        _containerInfo?.Dispose();
    }

Trouble-shooting

Troubleshooting Dynamically Generated Assembly

If configuration is loaded from configuration file, IoC.Configuration generates an assembly file which has a format DynamicallyGeneratedAssembly_timestamp.dll. Example is DynamicallyGeneratedAssembly_637851312217643417.dll.

Note

Refer to Loading from XML Configuration File for details on loading file based configuration

The dynamically generated assembly has classes for auto-generated services in elements autoService and autoServiceCustom under elements iocConfiguration/dependencyInjection/autoGeneratedServices and iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices, as well as some other auto-generated classes.

Note

The file is deleted, and a new file is generated when the configuration is loaded. In the future an improvement might be implemented to re-generate the assembly only if the configuration changed.

The folder where the dynamically generated DLL file is saved is determined by the value of attribute path in element iocConfiguration/appDataDir as in example below

1
2
3
4
5
<iocConfiguration
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">
    <appDataDir path="TestFiles\AutogeneratedDlls\DynamicFiles_AutoServiceTests" />
</iocConfiguration>

Below are some situations when the auto-generated assembly might fail to load, when configuration is loaded:

  • The code generated for autoServiceCustom by an implementation of IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator has invalid code.
  • The dynamically generated assembly references classes from other assemblies, and the assemblies that contain the classes are not added as references to dynamically generated assembly. To better resolve this issue, the rules used to add references to dynamically generated assembly are outlined below.

How Referenced Assemblies are Added to Dynamically Generated Assembly

There are number of ways, listed below, that IoC.Configuration can be instructed to add references to dynamically generated assembly.

  • Add referenced assembly file paths in property AdditionalReferencedAssemblies in class IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters, an instanceof which is used when loading the configuration from xml file, as demonstrated below:

  • Make sure the assembly is included in property OROptimizer.ILoadedAssemblies LoadedAssemblies { get; } in IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters that is used to load the XML configuration file. The property LoadedAssemblies of IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters is initialized in constructor, and in most cases an implementation OROptimizer.AllLoadedAssemblies can be used as demonstrated in example below.

    Note

    OROptimizer.AllLoadedAssemblies returns all assemblies loaded into application domain in property System.Collections.Generic.IEnumerable<Assembly> GetAssemblies().

Below is a demonstration of using properties AdditionalReferencedAssemblies and LoadedAssemblies in IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters to add references to dynamically generated assembly.
 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
using System.IO;
using IoC.Configuration.DiContainerBuilder.FileBased;
using NUnit.Framework;
using OROptimizer.Utilities.Xml;
using TestsSharedLibrary;

namespace IoC.Configuration.Tests.DocumentationTests.ReferencesInDynamicAssembly;

[TestFixture]
public class FileBasedConfigurationParameters_AdditionalReferencedAssemblies
{
    [Test]
    public void FileBasedConfigurationParameters_AdditionalReferencedAssemblies_Demo()
    {
        TestsHelper.SetupLogger();

        var fileBasedConfigurationParameters = new FileBasedConfigurationParameters(
            new FileBasedConfigurationFileContentsProvider(
                Path.Combine(Helpers.TestsEntryAssemblyFolder, @"DocumentationTests\AutoServiceCustom\DemoIoCConfiguration_autoServiceCustom.xml")),
            Helpers.TestsEntryAssemblyFolder,
            // LoadedAssembliesForTests is an implementation of ILoadedAssemblies that has a method
            // "IEnumerable<Assembly> GetAssemblies()" that returns list of assemblies to add as references to
            // generate dynamic assembly.
            new LoadedAssembliesForTests())
        {
            AdditionalReferencedAssemblies = new []
            {
                // List additional assemblies that should be added to dynamically generated assembly as references
                Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"),
                Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly2.dll")
            },
            AttributeValueTransformers = new[] {new FileFolderPathAttributeValueTransformer()},
            ConfigurationFileXmlDocumentLoaded = (sender, e) =>
                Helpers.EnsureConfigurationDirectoryExistsOrThrow(e.XmlDocument.SelectElement("/iocConfiguration/appDataDir").GetAttribute("path"))
        };

        var containerInfo = new DiContainerBuilder.DiContainerBuilder()
            .StartFileBasedDi(fileBasedConfigurationParameters, out _)
            .WithoutPresetDiContainer()
            .RegisterModules().Start();

        var autoImplementedInterfaceInstance = containerInfo.DiContainer.Resolve<IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface1>();
        Assert.AreEqual(10, autoImplementedInterfaceInstance.GetValue());
    }
}
  • Include the assembly in one of iocConfiguration/assemblies/assembly elements in configuration file. All assemblies specified in iocConfiguration/assemblies/assembly elements are added as references to dynamically generated assembly. However when the assembly is loaded, referenced assemblies are loaded to domain only if types in these assemblies are used in dynamic assembly.

    Note

    Refer to Assemblies and Probing Paths for details on using iocConfiguration/assemblies/assembly elements.

  • Add referenced assemblies in implementation of method GenerateCSharp in interface IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator when providing an implementation of an interface specified in element autoServiceCustom. Look at example below.

    Note

    Refer to Element autoServiceCustom for details on element autoServiceCustom.

 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
using System;
using System.IO;
using IoC.Configuration.ConfigurationFile;
using IoC.Configuration.DiContainer;
using OROptimizer.DynamicCode;

namespace IoC.Configuration.Tests.DocumentationTests.ReferencesInDynamicAssembly;

public class CustomAutoServiceCodeGeneratorDemo : ICustomAutoServiceCodeGenerator
{
    public void GenerateCSharp(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo,
        IDynamicAssemblyBuilder dynamicAssemblyBuilder,
        string generatedClassNamespace, string generatedClassName)
    {
        dynamicAssemblyBuilder.AddReferencedAssembly(
            Path.Combine(Helpers.GetTestFilesFolderPath(),
                @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"));

        dynamicAssemblyBuilder.AddReferencedAssembly(
            typeof(SharedServices.Interfaces.IInterface1));

        var classInfo = dynamicAssemblyBuilder.StartDynamicallyGeneratedClass(
            generatedClassName, generatedClassNamespace);

        var methodInfo = classInfo.StartMethod("GetValue", typeof(int),
            Array.Empty<IMethodParameterInfo>(),
            AccessLevel.Public, false, false);

        methodInfo.AddCodeLine("=> 10;");
    }

    public void Validate(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo)
    {

    }

    public void ValidateOnIoCContainerLoaded(IDiContainer diContainer,
        ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo)
    {

    }
}

Indices and tables