Powershell Factory Pattern as static method - powershell

I am looking to implement a tool that can manage files with a variety of locations; local files, UNC path files, files hosted on AWS, files hosted on a Synology NAS, etc. This will be done in PS 5.1 using classes and a number of specific patterns.
My thinking is I need a base path type, that has a property for the path itself. Then I need classes for UNC paths, local paths, AWS paths etc. that inherit form the base Path class. Then I can have a Copy class that handles the copy differently depending on the method signature. So UNC > UNC is handled differently from AWS > UNC. So, Strategy Pattern.
As for the path types, this seems like a place for the Factory Pattern. And every single example I have found on the internet for the Factory Pattern, in PowerShell, involves a dedicated Factory class. But it seems to me that logically, the Factory to create Path derivatives could/should be part of the Path class itself, as a static method. I searched on static factory method, and the concept is well documented for other languages, but not PowerShell. So I decided to just try it. To that end, I have this as a proof of concept...
class pxPath {
hidden $_path
pxPath () {}
pxPath ([string]$path) {
$this._path = $path
}
static [pxPath] Factory ([String]$path) {
[pxPath]$newPath = [uncFileSystem]::new($path)
return $newPath
}
}
class uncFileSystem : pxPath {
uncFileSystem ([String]$path) : base ([String]$path) {
}
}
$testPath = [pxPath]::Factory('\\Server\folder\file.txt')
$testPath.getType().FullName
$testPath._path
It doesn't have the multiple derived types needed for the Strategy Pattern, it just creates the one derived type. But it proves that a Factory as static method works.
My question is, is there some argument against this that I am not seeing, that explains why I have never seen an example like this for PowerShell? It makes SO much sense to me, and yet I have never seen it done, which really gives me pause.

Related

Alternative to Global Variable or Singleton

I have read in various places that Global variables are at best a code smell, and best avoided. At the moment I am working on refactoring a big function based PS script to classes, and thought to use a Singleton. The use case being a large data structure that will need to be referenced from a lot of different classes and modules.
Then I found this, which seems to suggest that Singletons are a bad idea too.
So, what IS the right way (in PS 5.1) to create a single data structure that needs to be referenced by a lot of classes, and modified by some of them? Likely pertinent is the fact that I do NOT need this to be thread safe. By definition the queue will be processed in a very linear fashion.
FWIW, I got to the referenced link looking for information on singletons and inheritance, since my singleton is simply one of a number of classes with very similar behavior, where I start with the singleton which contains collections of the next class, which each contain collections of the next class, to create a hierarchical queue. I wanted to have a base class that handled all the common queue management then extend that for the differing functionality lof each class. Which works great other than having that first extended class be a singleton. That seems to be impossible, correct?
EDIT: Alternatively, is it possible with this nested classes in a generic list property approach to be able to identify the parent from within a child? This is how I handled this is the Function based version. A global [XML] variable formed the data structure, and I could step through that structure, using .SelectNode() to populate a variable to pass to the next function down, and using .Parent to get information from higher up, and especially from the root of the data structure.
EDIT: Since I seem not to be able to paste code here right now, I have some code on GitHub. The example here of where the Singleton comes in is at line 121, where I need to verify if there are any other examples of the same task that have not yet comnepelted, so I can skip all but the last instance. This is a proof of concept for deleting common components of various Autodesk software, which is managed in a very ad hoc manner. So I want to be able to install any mix of programs (packages) and uninstall on any schedule, and ensure that the last package that has a shared component uninstall is the one that uninstalls it. So as to no break other dependent programs before that last uninstall happens. Hopefully that makes sense. Autodesk installs are a fustercluck of misery. If you don't have to deal with them, consider yourself lucky. :)
To complement Mathias R. Jessen's helpful answer - which may well be the best solution to your problem - with an answer to your original question:
So, what IS the right way (in PS 5.1) to create a single data structure that needs to be referenced by a lot of classes, and modified by some of them [without concern for thread safety]?
The main reason that global variables are to be avoided is that they are session-global, meaning that code that executes after your own sees those variables too, which can have side effects.
You cannot implement a true singleton in PowerShell, because PowerShell classes do not support access modifiers; notably, you cannot make a constructor private (non-public), you can only "hide" it with the hidden keyword, which merely makes it less discoverable while still being accessible.
You can approximate a singleton with the following technique, which itself emulates a static class (which PowerShell also doesn't support, because the static keyword is only supported on class members, not the class as a whole).
A simple example:
# NOT thread-safe
class AlmostAStaticClass {
hidden AlmostAStaticClass() { Throw "Instantiation not supported; use only static members." }
static [string] $Message # static property
static [string] DoSomething() { return ([AlmostAStaticClass]::Message + '!') }
}
[AlmostAStaticClass]::<member> (e.g., [AlmostAStaticClass]::Message = 'hi') can now be used in the scope in which AlmostAStaticClass was defined and all descendant scopes (but it is not available globally, unless the defining scope happens to be the global one).
If you need access to the class across module boundaries, you can pass it as a parameter (as a type literal); note that you still need :: to access the (invariably static) members; e.g.,
& { param($staticClass) $staticClass::DoSomething() } ([AlmostAStaticClass])
Implementing a thread-safe quasi-singleton - perhaps for use
with ForEach-Object -Parallel (v7+) or Start-ThreadJob (v6+, but installable on v5.1) - requires more work:
Note:
Methods are then required to get and set what are conceptually properties, because PowerShell doesn't support code-backed property getters and setters as of 7.0 (adding this ability is the subject of this GitHub feature request).
You still need an underlying property however, because PowerShell doesn't support fields; again the best you can do is to hide this property, but it is technically still accessible.
The following example uses System.Threading.Monitor (which C#'s lock statement is based on) to manage thread-safe access to a value; for managing concurrent adding and removing items from collections, use the thread-safe collection types from the System.Collections.Concurrent namespace.
# Thread-safe
class AlmostAStaticClass {
static hidden [string] $_message = '' # conceptually, a *field*
static hidden [object] $_syncObj = [object]::new() # sync object for [Threading.Monitor]
hidden AlmostAStaticClass() { Throw "Instantiation not supported; use only static members." }
static SetMessage([string] $text) {
Write-Verbose -vb $text
# Guard against concurrent access by multiple threads.
[Threading.Monitor]::Enter([AlmostAStaticClass]::_syncObj)
[AlmostAStaticClass]::_message = $text
[Threading.Monitor]::Exit([AlmostAStaticClass]::_syncObj)
}
static [string] GetMessage() {
# Guard against concurrent access by multiple threads.
# NOTE: This only works with [string] values and instances of *value types*
# or returning an *element from a collection* that is
# only subject to concurrency in terms of *adding and removing*
# elements.
# For all other (reference) types - entire (non-concurrent)
# collections or individual objects whose properties are
# themselves subject to concurrent access, the *calling* code
# must perform the locking.
[Threading.Monitor]::Enter([AlmostAStaticClass]::_syncObj)
$msg = [AlmostAStaticClass]::_message
[Threading.Monitor]::Exit([AlmostAStaticClass]::_syncObj)
return $msg
}
static [string] DoSomething() { return ([AlmostAStaticClass]::GetMessage() + '!') }
}
Note that, similar to crossing module boundaries, using threads too requires passing the class as a type object to other threads, which, however is more conveniently done with the $using: scope specifier; a simple (contrived) example:
# !! BROKEN AS OF v7.0
$class = [AlmostAStaticClass]
1..10 | ForEach-Object -Parallel { ($using:class)::SetMessage($_) }
Note: This cross-thread use is actually broken as of v7.0, due to classes currently being tied to the defining runspace - see this GitHub issue. It is to be seen if a solution will be provided.
As you can see, the limitations of PowerShell classes make implementing such scenarios cumbersome; using Add-Type with ad hoc-compiled C# code is worth considering as an alternative.
This GitHub meta issue is a compilation of various issues relating to PowerShell classes; while they may eventually get resolved, it is unlikely that PowerShell's classes will ever reach feature parity with C#; after all, OOP is not the focus of PowerShell's scripting language (except with respect to using preexisting objects).
As mentioned in the comments, nothing in the code you linked to requires a singleton.
If you want to retain a parent-child relationship between your ProcessQueue and related Task instance, that can be solved structurally.
Simply require injection of a ProcessQueue instance in the Task constructor:
class ProcessQueue
{
hidden [System.Collections.Generic.List[object]]$Queue = [System.Collections.Generic.List[object]]::New()
}
class Task
{
[ProcessQueue]$Parent
[string]$Id
Task([string]$id, [ProcessQueue]$parent)
{
$this.Parent = $parent
$this.Id = $id
}
}
When instantiating the object hierarchy:
$myQueue = [ProcessQueue]::new()
$myQueue.Add([Task]#{ Id = "id"; Parent = $myQueue})
... or refactor ProcessQueue.Add() to take care of constructing the task:
class ProcessQueue
{
[Task] Add([string]$Id){
$newTask = [Task]::new($Id,$this)
$Queue.Add($newTask)
return $newTask
}
}
At which point you just use ProcessQueue.Add() as a proxy for the [Task] constructor:
$newTask = $myQueue.Add($id)
$newTask.DisplayName = "Display name goes here"
Next time you need to search related tasks from a single Task instance, you just do:
$relatedTasks = $task.Parent.Find($whatever)

Any way to trigger creation of a list of all classes in a hierarchy in Swift 4?

Edit: So far it looks like the answer to my question is, "You can't do that in Swift." I currently have a solution whereby the subclass names are listed in an array and I loop around and instantiate them to trigger the process I'm describing below. If this is the best that can be done, I'll switch it to a plist so that least it's externally defined. Another option would be to scan a directory and load all files found, then I would just need to make sure the compiler output for certain classes is put into that directory...
I'm looking for a way to do something that I've done in C++ a few times. Essentially, I want to build a series of concrete classes that implement a particular protocol, and I want to those classes to automatically register themselves such that I can obtain a list of all such classes. It's a classic Prototype pattern (see GoF book) with a twist.
Here's my approach in C++; perhaps you can give me some ideas for how to do this in Swift 4? (This code is grossly simplified, but it should demonstrate the technique.)
class Base {
private:
static set<Base*> allClasses;
Base(Base &); // never defined
protected:
Base() {
allClasses.put(this);
}
public:
static set<Base*> getAllClasses();
virtual Base* clone() = 0;
};
As you can see, every time a subclass is instantiated, a pointer to the object will be added to the static Base::allClasses by the base class constructor.
This means every class inherited from Base can follow a simple pattern and it will be registered in Base::allClasses. My application can then retrieve the list of registered objects and manipulate them as required (clone new ones, call getter/setter methods, etc).
class Derived: public Base {
private:
static Derived global; // force default constructor call
Derived() {
// initialize the properties...
}
Derived(Derived &d) {
// whatever is needed for cloning...
}
public:
virtual Derived* clone() {
return new Derived(this);
}
};
My main application can retrieve the list of objects and use it to create new objects of classes that it knows nothing about. The base class could have a getName() method that the application uses to populate a menu; now the menu automatically updates when new subclasses are created with no code changes anywhere else in the application. This is a very powerful pattern in terms of producing extensible, loosely coupled code...
I want to do something similar in Swift. However, it looks like Swift is similar to Java, in that it has some kind of runtime loader and the subclasses in this scheme (such as Derived) are not loaded because they're never referenced. And if they're not loaded, then the global variable never triggers the constructor call and the object isn't registered with the base class. Breakpoints in the subclass constructor shows that it's not being invoked.
Is there a way to do the above? My goal is to be able to add a new subclass and have the application automatically pick up the fact that the class exists without me having to edit a plist file or doing anything other than writing the code and building the app.
Thanks for reading this far — I'm sure this is a bit of a tricky question to comprehend (I've had difficulty in the past explaining it!).
I'm answering my own question; maybe it'll help someone else.
My goal is to auto initialize subclasses such that they can register with a central authority and allow the application to retrieve a list of all such classes. As I put in my edited question, above, there doesn't appear to be a way to do this in Swift. I have confirmed this now.
I've tried a bunch of different techniques and nothing seems to work. My goal was to be able to add a .swift file with a class in it and rebuild, and have everything automagically know about the new class. I will be doing this a little differently, though.
I now plan to put all subclasses that need to be initialized this way into a particular directory in my application bundle, then my AppDelegate (or similar class) will be responsible for invoking a method that scans the directory using the filenames as the class names, and instantiating each one, thus building the list of "registered" subclasses.
When I have this working, I'll come back and post the code here (or in a GitHub project and link to it).
Same boat. So far the solution I've found is to list classes manually, but not as an array of strings (which is error-prone). An a array of classes such as this does the job:
class AClass {
class var subclasses: [AClass.Type] {
return [BClass.self, CClass.self, DClass.self]
}
}
As a bonus, this approach allows me to handle trees of classes, simply by overriding subclasses in each subclass.

How to export a class in a PowerShell v5 module

I've got a module setup to be like a library for a few other scripts. I can't figure out how to get a class declaration into the script scope calling Import-Module. I tried to arrange Export-Module with a -class argument, like the -function, but there isn't a -class available. Do I just have to declare the class in every script?
The setup:
holidays.psm1 in ~\documents\windows\powershell\modules\holidays\
active script calls import-module holidays
there is another function in holidays.psm1 that returns a class object correctly, but I don't know how to create new members of the class from the active script after importing
Here is what the class looks like:
Class data_block
{
$array
$rows
$cols
data_block($a, $r, $c)
{
$this.array = $a
$this.rows = $r
$this.cols = $c
}
}
PSA: There is a known issue that keeps old copies of classes in memory. It makes working with classes really confusing if you don't know about it. You can read about it here.
using is Prone to Pitfalls
The using keyword is prone to various pitfalls as follows:
The using statement does not work for modules not in PSModulePath unless you specify the module's full path in the using statement. This is rather surprising because although a module is available via Get-Module the using statement may not work depending on how the module was loaded.
The using statement can only be used at the very beginning of a "script". No combination of [scriptblock]::Create() or New-Module seems overcome this. A string passed to Invoke-Expression seems to act as a sort of standalone script; a using statement at the beginning of such a string sort of works. That is, Invoke-Expression "using module $path" can succeed but the scope into which the contents of the module are made available seems rather inscrutable. For example, if Invoke-Expression "using module $path" is used inside a Pester scriptblock, the classes inside the module are not available from the same Pester scriptblock.
The above statements are based on this set of tests.
ScriptsToProcess Prevents Access to Private Module Functions
Defining a class in a script referred to by the module manifest's ScriptsToProcess seems at first glance to export the class from the module. However, instead of exporting the class, it "creates the class in the global SessionState instead of the module's, so it...can't access private functions". As far as I can tell, using ScriptsToProcess is like defining the class outside the module in the following manner:
# this is like defining c in class.ps1 and referring to it in ScriptsToProcess
class c {
[string] priv () { return priv }
[string] pub () { return pub }
}
# this is like defining priv and pub in module.psm1 and referring to it in RootModule
New-Module {
function priv { 'private function' }
function pub { 'public function' }
Export-ModuleMember 'pub'
} | Import-Module
[c]::new().pub() # succeeds
[c]::new().priv() # fails
Invoking this results in
public function
priv : The term 'priv' is not recognized ...
+ [string] priv () { return priv } ...
The module function priv is inaccessible from the class even though priv is called from a class that was defined when that module was imported. This might be what you want, but I haven't found a use for it because I have found that class methods usually need access to some function in the module that I want to keep private.
.NewBoundScriptBlock() Seems to Work Reliably
Invoking a scriptblock bound to the module containing the class seems to work reliably to export instances of a class and does not suffer from the pitfalls that using does. Consider this module which contains a class and has been imported:
New-Module 'ModuleName' { class c {$p = 'some value'} } |
Import-Module
Invoking [c]::new() inside a scriptblock bound to the module produces an object of type [c]:
PS C:\> $c = & (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
PS C:\> $c.p
some value
Idiomatic Alternative to .NewBoundScriptBlock()
It seems that there is a shorter, idiomatic alternative to .NewBoundScriptBlock(). The following two lines each invoke the scriptblock in the session state of the module output by Get-Module:
& (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
& (Get-Module 'ModuleName') {[c]::new()}}
The latter has the advantage that it will yield flow of control to the pipeline mid-scriptblock when an object is written to the pipeline. .NewBoundScriptBlock() on the other hand collects all objects written to the pipeline and only yields once execution of the entire scriptblock has completed.
I found a way to load the classes without the need of "using module".
In your MyModule.psd1 file use the line:
ScriptsToProcess = #('Class.ps1')
And then put your classes in the Class.ps1 file:
class MyClass {}
Update: Although you don't have to use "using module MyModule" with this method you still have to either:
Run "using module MyModule"
Or run "Import-Module MyModule"
Or call any function in your module (so it will auto import your module on the way)
Update2: This will load the Class to the current scope so if you import the Module from within a function for example the Class will not be accessible outside of the function. Sadly the only reliable method I see is to write your Class in C# and load it with Add-Type -Language CSharp -TypeDefinition 'MyClass...'.
According to here and here, you can use classes defined in your module by doing the following in PowerShell 5:
using module holidays
The using statement is the way to go if it works for you. Otherwise this seems to work as well.
File testclass.psm1
Use a function to deliver the class
class abc{
$testprop = 'It Worked!'
[int]testMethod($num){return $num * 5}
}
function new-abc(){
return [abc]::new()
}
Export-ModuleMember -Function new-abc
File someScript.ps1
Import-Module path\to\testclass.psm1
$testclass = new-abc
$testclass.testProp # Returns 'It Worked!'
$testclass.testMethod(500) # Returns 2500
$testclass | gm
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
testMethod Method int testMethod(System.Object num)
ToString Method string ToString()
testprop Property System.Object testprop {get;set;}
You pretty much cannot. According to about_Classes help:
Class keyword
Defines a new class. This is a true .NET Framework type. Class members are public, but only public within the module scope. You can't refer to the type name as a string (for example, New-Object doesn't work), and in this release, you can't use a type literal (for example, [MyClass]) outside the script/module file in which the class is defined.
This means, if you want to get yourself a data_block instance or use functions that operate those classes, make a function, say, New-DataBlock and make it return a new data_block instance, which you can then use to get class methods and properties (likely including static ones).
This certainly does not work as expected.
The idea in PowerShell 5 is that you can define your class in a separate file with a .psm1 extension.
Then you can load the definition with the command (e.g.):
using module C:\classes\whatever\path\to\file.psm1
This must be the first line in your script (after comments).
What causes so much pain is that even if the class definitions are called from a script, the modules are loaded for the entire session. You can see this by running:
Get-Module
You will see the name of the file you loaded. No matter if you run the script again, it will not reload the class definitions! (It won't even read the psm1 file.) This causes much gnashing of teeth.
Sometimes - sometimes - you can run this command before running the script, which will reload the module with refreshed class definitions:
Remove-Module file
where file is the name without path or extension. However, to save your sanity I recommend restarting the PowerShell session. This is obviously cumbersome; Microsoft needs to clean this up somehow.
I've encountered multiple issues regarding PowerShell classes in v5 as well.
I've decided to use the following workaround for now, as this is perfectly compatible with .NET and PowerShell:
Add-Type -Language CSharp -TypeDefinition #"
namespace My.Custom.Namespace {
public class Example
{
public string Name { get; set; }
public System.Management.Automation.PSCredential Credential { get; set; }
// ...
}
}
"#
The benefit is that you don't need a custom assembly to add a type definition. You can add the class definition inline in your PowerShell scripts or modules.
The only downside is that you will need to create a new runtime to reload the class definition after is has been loaded for the first time (just like loading assemblies in a C#/.NET domain).
The way I've worked around this problem is to move your custom class definition into an empty .ps1 file with the same name (like you would in Java/C#), and then load it into both the module definition and your dependent code by dot sourcing. I know this isn't great, but to me it's better than having to maintain multiple definitions of the same class across multiple files...
To update class definitions while developing, select the code for the class and press F8 to run the selected code. It is not as clean as the -Force option on the Import-Module command.
Seeing as using Module doesn't have that option and Remove-Module is sporadic at best, this is the best way I have found to develop a class and see the results without having to close down the PowerShell ISE and start it up again.
A surprising & cumbersome limitation of using module appears to be that any classes to expose outside of a module MUST be in the module's psm1 file itself.
A class definition to expose outside the module cannot be 'dotsourced' into the psm1 file from a separate ps1 file in the module
...this is as per the docs since v5.1 (to at least 7.2):
The using module statement imports classes from the root module
(ModuleToProcess) of a script module or binary module. It does not
consistently import classes defined in nested modules or classes
defined in scripts that are dot-sourced into the module. Classes that
you want to be available to users outside of the module should be
defined in the root module.
So therefore, it seems the simplest options (as discussed in other answers) are:
If you only need to reference class instances outside of its defining module, create public functions to return class instances:
function Get-MyModulesClass { [MyModuleClass]::New() }
To reference a class type outside of the module (eg specifing a function argument's type), the class must have been defined directly in the psm1 file of the module, and this psm1 file must have been included in your external script via using module (eg using module <relativePathToModulePsm1File>).
...and of course what doesn't help when figuring all this out is that classes don't reload so you need start a new powershell session every time you make a change to the classes.
Example Module
/MyLibaryModule/MyPrivateClass.ps1:
class MyPrivateClass {
[void] Test(){ Write-Host "Accessed private class methods!"}
}
/MyLibaryModule/MyLibraryModule.psm1
class MyPublicClass {} # Exposed classes MUST be defined in this file
. $PSScriptRoot\MyPrivateClass.ps1
function Get-MyPrivateClassInstance { [MyPrivateClass]::new()}
/ExampleScript.ps1
using module .\MyLibraryModule\MyLibraryModule.psm1
[MyPublicClass]$myVar1 # Works
[MyPrivateClass]$myVar2 # Errors
Import-Module .\MyLibraryModule\MyLibraryModule.psm1
$object = Get-MyPrivateClassInstance
$object.GetType().Name
$object.Test() # works
Output
InvalidOperation:
Line |
5 | [MyPrivateClass]$myVar2 # Errors
| ~~~~~~~~~~~~~~
| Unable to find type [MyPrivateClass].
MyPrivateClass
Accessed private class methods!

Dealing with state in factory implementations

What pattern would one use if you have multiple factory implementations, each of which requires different state information to create new objects?
Example:
IModelParameters: contains all the inputs and outputs to a complex calculation
IModelParameterFactory: has methods for getting and saving IModelParameter objects.
The issue is that one factory implementation might be getting your parameters from a database, with some state needed for retrieval, (i.e. a UserID), another might be getting your inputs from a file, in which case you don't have a UserID, but you do need a file name.
Is there another pattern that works better in this case? I've looked at some dependancy injection tools/libraries, and haven't seen anything that seems to address the situation.
Have you tried to put the requeriments in a class?
Every factory implementation has their own requeriments, but all requeriments classes derives form a base requeriment class (Or impements a requeriments interface). This allows you to have the same interface for all factory implementations, you just must do a cast to the correct requeriments class in every factory implementation.
Yes, casts are ugly and error-prone, but this method provides an uniform an extensible interface for your factory.
It's hard to say without seeing some code, but you may want to look into implementing a Repository Pattern. The Repository implementation would be responsible for retrieving the data that the factory then used to build its object(s). You could inject the repository interface into your factory:
public class ModelParameterFactory : IModelParameterFactory
{
private readonly IModelParameterRepository Repository;
public ModelParameterFactory(IModelParameterRepository repository)
{
Repository = repository;
}
...interface methods use the injected repository...
}
Then you would have, say a DatabaseModelParameterRepository and a FileModelParameterRepository. But I'm guessing you also have logic around which of those you would need to inject, so that calls for another factory:
public class ModelParameterRepositoryFactory : IModelParameterRepositoryFactory
{
public ModelParameterRepositoryFactory(...inputs needed to determine which repository to use...)
{
...assign...
}
...determine which repository is required and return it...
}
At this point, it might make more sense to inject IModelParameterRepositoryFactory into the ModelParameterFactory, rather than inject the IModelParameterRepository.
public class ModelParameterFactory : IModelParameterFactory
{
private readonly IModelParameterRepositoryFactory RepositoryFactory;
public ModelParameterFactory(IModelParameterRepositoryFactory repositoryFactory)
{
RepositoryFactory = repositoryFactory;
}
...interface methods get repository from the factory...
}
Whether you use a DI container or not, all logic regarding which repository to use and which factory to use are now moved into the relevant factory implementations, as opposed to the calling code or DI configuration.
While not terribly complex, this design nonetheless does give me pause to wonder whether your ModelParameterFactory and ModelParameters are too generic. You might benefit from teasing them into separate, more specific classes. The result would be a simpler and more expressive design. The above should work for you if that is not the case, however.
In my point of view, a state is something that you store in memory, such as static object, global variable, cache or session. Usually in DI, such states are not maintained, but being passed as a parameter. Example:
public IEnumerable<Records> GetRecordByUserId(string userId){ /*code*/ }
The userId is being passed instead being maintained in the repository.
However, when you want to make them as configuration-like instead of passing each time you do query, I think you can inject it as a wrapper class. See my question for more info. However, I don't recommend this design at repository, but I do recommend at service level.

Class design: file conversion logic and class design

This is pretty basic, but sort of a generic issue so I want to hear what people's thoughts are. I have a situation where I need to take an existing MSI file and update it with a few standard modifications and spit out a new MSI file (duplication of old file with changes).
I started writing this with a few public methods and a basic input path for the original MSI. The thing is, for this to work properly, a strict path of calls has to be followed from the caller:
var custom = CustomPackage(sourcemsipath);
custom.Duplicate(targetmsipath);
custom.Upgrade();
custom.Save();
custom.WriteSmsXmlFile(targetxmlpath);
Would it be better to put all the conversion logic as part of the constructor instead of making them available as public methods? (in order to avoid having the caller have to know what the "proper order" is):
var custom = CustomPackage(sourcemsipath, targetmsipath); // saves converted msi
custom.WriteSmsXmlFile(targetxmlpath); // saves optional xml for sms
The constructor would then directly duplicate the MSI file, upgrade it and save it to the target location. The "WriteSmsXmlFile is still a public method since it is not always required.
Personally I don't like to have the constructor actually "do stuff" - I prefer to be able to call public methods, but it seems wrong to assume that the caller should know the proper order of calls?
An alternative would be to duplicate the file first, and then pass the duplicated file to the constructor - but it seems better to have the class do this on its own.
Maybe I got it all backwards and need two classes instead: SourcePackage, TargetPackage and pass the SourcePackage into the constructor of the TargetPackage?
I'd go with your first thought: put all of the conversion logic into one place. No reason to expose that sequence to users.
Incidentally, I agree with you about not putting actions into a constructor. I'd probably not do this in the constructor, and instead do it in a separate converter method, but that's personal taste.
It may be just me, but the thought of a constructor doing all these things makes me shiver. But why not provide a static method, which does all this:
public class CustomPackage
{
private CustomPackage(String sourcePath)
{
...
}
public static CustomPackage Create(String sourcePath, String targetPath)
{
var custom = CustomPackage(sourcePath);
custom.Duplicate(targetPath);
custom.Upgrade();
custom.Save();
return custom;
}
}
The actual advantage of this method is, that you won't have to give out an instance of CustomPackage unless the conversion process actually succeeded (safe of the optional parts).
Edit In C#, this factory method can even be used (by using delegates) as a "true" factory according to the Factory Pattern:
public interface ICustomizedPackage
{
...
}
public class CustomPackage: ICustomizedPackage
{
...
}
public class Consumer
{
public delegate ICustomizedPackage Factory(String,String);
private Factory factory;
public Consumer(Factory factory)
{
this.factory = factory;
}
private ICustomizedPackage CreatePackage()
{
return factory.Invoke(..., ...);
}
...
}
and later:
new Consumer(CustomPackage.Create);
You're right to think that the constructor shouldn't do any more work than to simply initialize the object.
Sounds to me like what you need is a Convert(targetmsipath) function that wraps the calls to Duplicate, Upgrade and Save, thereby removing the need for the caller to know the correct order of operations, while at the same time keeping the logic out of the constructor.
You can also overload it to include a targetxmlpath parameter that, when supplied, also calls the WriteSmsXmlFile function. That way all the related operations are called from the same function on the caller's side and the order of operations is always correct.
In such situations I typicaly use the following design:
var task = new Task(src, dst); // required params goes to constructor
task.Progress = ProgressHandler; // optional params setup
task.Run();
I think there are service-oriented ways and object-oritented ways.
The service-oriented way would be to create series of filters that passes along an immutable data transfer object (entity).
var service1 = new Msi1Service();
var msi1 = service1.ReadFromFile(sourceMsiPath);
var service2 = new MsiCustomService();
var msi2 = service2.Convert(msi1);
service2.WriteToFile(msi2, targetMsiPath);
service2.WriteSmsXmlFile(msi2, targetXmlPath);
The object-oriented ways can use decorator pattern.
var decoratedMsi = new CustomMsiDecorator(new MsiFile(sourceMsiPath));
decoratedMsi.WriteToFile(targetMsiPath);
decoratedMsi.WriteSmsXmlFile(targetXmlPath);