How do I create an interactive Powershell instance from C#? - c#

I have a Powershell script that requires user interaction. I can call powershell.exe from C# using System.Diagnostics.Process and pass the scripts path as a parameter but I would like the script to be an embedded resource of the project. I tried creating a Runspace (see below) and running the script but because the script requires user interaction I receive an exception.
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "mynamespace.myscriptfile.ps1";
string result = "";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
Console.WriteLine(result);
}
//Create Powershell Runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
// Create pipeline and add commands
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(result);
// Execute Script
Collection<PSObject> results = new Collection<PSObject>();
try
{
results = pipeline.Invoke();
}
catch (Exception ex)
{
results.Add(new PSObject((object)ex.Message));
}
runspace.Close();
Console.ReadKey();
Is there a way to either pass the embedded resource to powershell.exe using System.Diagnostics.Process or is there a way to Invoke the script from C# where the user can interact?
UPDATE:
It seems to me that I may be able to use an implementation of the abstract class PSHost along with using the PSHostUserInterface property correctly, I may be able to create a Runspace that takes the PSHost implementation as a parameter to use the native Powershell console. I have been trying to test the idea but I'm not quite sure how to implement the abstract class.
Below is a sample of code that I obtained from Microsoft. I am confused with a couple of things. If it matters I will be creating the Runspace in a console application with a namespace called: WebRequirements in the Program class.
private Host01 program; (Would Host01 be Program?)
PSHostUserInterface (Is this where I would dictate that I want to use a native Powershell host and if so how would I do that?)
internal class MyHost : PSHost
{
///
/// A reference to the PSHost implementation.
///
private Host01 program;
/// <summary>
/// The culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalCultureInfo =
System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// The UI culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalUICultureInfo =
System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// The identifier of this PSHost implementation.
/// </summary>
private Guid myId = Guid.NewGuid();
/// <summary>
/// Initializes a new instance of the MyHost class. Keep
/// a reference to the host application object so that it
/// can be informed of when to exit.
/// </summary>
/// <param name="program">
/// A reference to the host application object.
/// </param>
public MyHost(Host01 program)
{
this.program = program;
}
/// <summary>
/// Return the culture information to use. This implementation
/// returns a snapshot of the culture information of the thread
/// that created this object.
/// </summary>
public override System.Globalization.CultureInfo CurrentCulture
{
get { return this.originalCultureInfo; }
}
/// <summary>
/// Return the UI culture information to use. This implementation
/// returns a snapshot of the UI culture information of the thread
/// that created this object.
/// </summary>
public override System.Globalization.CultureInfo CurrentUICulture
{
get { return this.originalUICultureInfo; }
}
/// <summary>
/// This implementation always returns the GUID allocated at
/// instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return this.myId; }
}
/// <summary>
/// Return a string that contains the name of the host implementation.
/// Keep in mind that this string may be used by script writers to
/// identify when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}
/// <summary>
/// This sample does not implement a PSHostUserInterface component so
/// this property simply returns null.
/// </summary>
public override PSHostUserInterface UI
{
get { return null; }
}
/// <summary>
/// Return the version object for this application. Typically this
/// should match the version resource in the application.
/// </summary>
public override Version Version
{
get { return new Version(1, 0, 0, 0); }
}
/// <summary>
/// Not implemented by this example class. The call fails with
/// a NotImplementedException exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
/// <summary>
/// Not implemented by this example class. The call fails
/// with a NotImplementedException exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
/// <summary>
/// This API is called before an external application process is
/// started. Typically it is used to save state so the parent can
/// restore state that has been modified by a child process (after
/// the child exits). In this example, this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyBeginApplication()
{
return;
}
/// <summary>
/// This API is called after an external application process finishes.
/// Typically it is used to restore state that a child process may
/// have altered. In this example, this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyEndApplication()
{
return;
}
/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode">The exit code to use.</param>
public override void SetShouldExit(int exitCode)
{
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
}
}

Related

Avoid non-readonly static fields - Immutability NDepend

I am using NDepend for code analysis and got this warning:
https://www.ndepend.com/default-rules/NDepend-Rules-Explorer.html?ruleid=ND1901#!
This rule warns about static fields that are not declared as read-only.
In Object-Oriented-Programming the natural artifact to hold states that can be modified is instance fields. Such mutable static fields create confusion about the expected state at runtime and impairs the code testability since the same mutable state is re-used for each test.
My code is as follows:
using Cosmonaut;
using Microsoft.Azure.Documents.Client;
using System.Configuration;
using LuloWebApi.Entities;
namespace LuloWebApi.Components
{
/// <summary>
/// Main class that encapsulates the creation of instances to connecto to Cosmos DB
/// </summary>
public sealed class CosmosStoreHolder
{
/// <summary>
/// Property to be initiated only once in the constructor (singleton)
/// </summary>
private static CosmosStoreHolder instance = null;
/// <summary>
/// To block multiple instance creation
/// </summary>
private static readonly object padlock = new object();
/// <summary>
/// CosmosStore object to get tenants information
/// </summary>
public Cosmonaut.ICosmosStore<SharepointTenant> CosmosStoreTenant { get; }
/// <summary>
/// CosmosStore object to get site collection information
/// </summary>
public Cosmonaut.ICosmosStore<SiteCollection> CosmosStoreSiteCollection { get; }
/// <summary>
/// CosmosStore object to get page templates information
/// </summary>
public Cosmonaut.ICosmosStore<PageTemplate> CosmosStorePageTemplate { get; }
/// <summary>
/// CosmosStore object to get pages information
/// </summary>
public Cosmonaut.ICosmosStore<Page> CosmosStorePage { get; }
/// <summary>
/// CosmosStore object to get roles information
/// </summary>
public Cosmonaut.ICosmosStore<Role> CosmosStoreRole { get; }
/// <summary>
/// CosmosStore object to get clients information
/// </summary>
public Cosmonaut.ICosmosStore<Client> CosmosStoreClient { get; }
/// <summary>
/// CosmosStore object to get users information
/// </summary>
public Cosmonaut.ICosmosStore<User> CosmosStoreUser { get; }
/// <summary>
/// CosmosStore object to get partners information
/// </summary>
public Cosmonaut.ICosmosStore<Partner> CosmosStorePartner { get; }
/// <summary>
/// CosmosStore object to get super administrators information
/// </summary>
public Cosmonaut.ICosmosStore<SuperAdministrator> CosmosStoreSuperAdministrator { get; }
/// <summary>
/// Constructor
/// </summary>
CosmosStoreHolder()
{
CosmosStoreSettings settings = new Cosmonaut.CosmosStoreSettings(ConfigurationManager.AppSettings["database"].ToString(),
ConfigurationManager.AppSettings["endpoint"].ToString(),
ConfigurationManager.AppSettings["authKey"].ToString());
settings.ConnectionPolicy = new ConnectionPolicy
{
ConnectionMode = ConnectionMode.Direct,
ConnectionProtocol = Protocol.Tcp
};
CosmosStoreTenant = new CosmosStore<SharepointTenant>(settings);
CosmosStoreSiteCollection = new CosmosStore<SiteCollection>(settings);
CosmosStorePageTemplate = new CosmosStore<PageTemplate>(settings);
CosmosStorePage = new CosmosStore<Page>(settings);
CosmosStoreRole = new CosmosStore<Role>(settings);
CosmosStoreClient = new CosmosStore<Client>(settings);
CosmosStoreUser = new CosmosStore<User>(settings);
CosmosStorePartner = new CosmosStore<Partner>(settings);
CosmosStoreSuperAdministrator = new CosmosStore<SuperAdministrator>(settings);
}
/// <summary>
/// Instance access, singleton
/// </summary>
public static CosmosStoreHolder Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new CosmosStoreHolder();
}
return instance;
}
}
}
}
}
However I am not sure how to fix this warning.
This is a guide, not a hard rule. Usually, non-readonly static fields are hard to intuit about. But in this case you're doing lazy deferred loading, so... a lock and mutate is indeed one way of achieving that, without causing it to be loaded prematurely.
So a pragmatic fix is: just ignore/override the warning
Another approach, however, is to move the field to another type where it is readonly, and rely on the deferred .cctor semantics:
public static CosmosStoreHolder Instance {
[MethodImpl(MethodImplOptions.NoInlining)]
get => DeferredHolder.Instance;
}
private static class DeferredHolder {
internal static readonly CosmosStoreHolder Instance = new CosmosStoreHolder();
}
Then you don't even need the lock semantics (.cctor deals with that for you).

C# Custom Code Coverage Integration in Visual Studio 2013

I would like to enhance efficiency in our software department by providing a VS extension or add in to perform custom code coverage using VS 2013.
The special point in that enterprise is the coverage of special code snippet actually marked by a comment like //INDISPENSABLE_STUFF document comment that is defined as a task token.
I was thinking of introducing a new attribute RiskAttribute to qualify methods for instance but could not separate the corresponding code coverage result from the rest for reporting how much of the indispensable stuff has been covered.
/// <summary>
/// Risk Attribute
/// </summary>
public class RiskAttribute : Attribute
{
private readonly string _document;
private readonly string _comment;
/// <summary>
/// Constructor
/// </summary>
/// <param name="doc"></param>
/// <param name="comment"></param>
public RiskAttribute(string doc, string comment)
{
_document = doc;
_comment = comment;
}
/// <summary>
/// Document
/// </summary>
public string Document { get { return _document; } }
/// <summary>
/// Comment
/// </summary>
public string Comment { get { return _comment; } }
}
I turned to implement an add in but do not figure out in the 1. step how to launch the vs code coverage tool programmatically for a project using my add-in. The 2. step would be to customize the code coverage in order to parse the custom task token and return a result like xy% of defined task token INDISPENSABLE_STUFF is covered.
For development, I implemented a calculator class with unit test to exercise both variations:
The class
/// <summary>
/// Calculator
/// </summary>
public class Calculator
{
/// <summary>
/// Addition
/// INDISPENSABLE_STUFF (DOC #2150) Test
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static decimal Add(decimal a, decimal b) { return a + b; }
/// <summary>
/// Substraction
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
[RiskAttribute("DOC #2150", "Test")]
public static decimal Sub(decimal a, decimal b) { return a - b; }
}
The unit test
/// <summary>
/// Test class for Calculator
/// </summary>
[TestClass]
public class CalculatorTest
{
/// <summary>
/// Tests addition
/// </summary>
[TestMethod]
public void Test_Sub()
{
decimal a = 1;
decimal b = 2;
Assert.AreEqual((a - b), Calculator.Sub(a, b));
}
}
So now, for the question, I already have to add-in code for the integration but miss the main content to start the customized code coverage. Does anybody know :
how to adapt the code coverage to consider task token?
how to start the code coverage programmatically?
Sorry if these are "big" points for only "one" question.
Thanks

Type.GetConstructor returns null on Iphone

I am developing an app in Xamarin for Iphone, android version of similar app is ready for Google play. I am using jabber-net library in my app for chat functionality. But having some issue on device(Iphone 5 - IOS 7.0.3). this issue doesn't occur in emulator following is the method code.
public class QnameType
{
/// <summary>
/// Element name
/// </summary>
protected internal string Name;
/// <summary>
/// Element namespace URI
/// </summary>
protected internal string NS;
/// <summary>
/// Type to create for NS/Name pair
/// </summary>
protected internal Type ElementType;
/// <summary>
/// Create a QnameType
/// </summary>
/// <param name="name"></param>
/// <param name="ns"></param>
/// <param name="typ"></param>
public QnameType(string name, string ns, Type typ)
{
this.Name = name;
this.NS = ns;
this.ElementType = typ;
}
/// <summary>
/// Is this the same qname by element name and namespace?
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == (object)this)
return true;
QnameType other = obj as QnameType;
if (other == null)
return false;
return (other.Name == Name) && (other.NS == NS);
}
/// <summary>
/// Get a hash over the name and namespace.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return ToString().GetHashCode();
}
/// <summary>
/// Namespace|Name
/// </summary>
/// <returns></returns>
public override string ToString()
{
return NS + "|" + Name;
}
}
public interface IPacketTypes
{
/// <summary>
/// QName to type mappings.
/// </summary>
QnameType[] Types { get; }
}
public class ElementFactory
{
private Hashtable m_types = new Hashtable();
private static readonly Type[] s_constructorTypes =
new Type[] { typeof(string),
typeof(XmlQualifiedName),
typeof(XmlDocument) };
public void AddType(IPacketTypes list)
{
foreach (QnameType qn in list.Types)
{
this.AddType(qn.Name, qn.NS, qn.ElementType);
}
}
public void AddType(string localName, string ns, Type t)
{
Debug.Assert(t.IsSubclassOf(typeof(Element)));
ConstructorInfo ci = t.GetConstructor(s_constructorTypes);
Debug.Assert(ci != null);
AddType(new XmlQualifiedName(localName, ns), ci);
}
public Element GetElement(string prefix, XmlQualifiedName qname, XmlDocument doc)
{
ConstructorInfo ci = (ConstructorInfo) m_types[qname];
if (ci == null)
{
return new Element(prefix, qname, doc);
}
return (Element) ci.Invoke
(new object[] {prefix, qname, doc});
}
/// <summary>
/// Get a constructor for the appropriate type for the given qname.
/// </summary>
public ConstructorInfo this[XmlQualifiedName qname]
{
get { return (ConstructorInfo) m_types[qname]; }
}
}
t.GetConstructor() returns null on Iphone but works fine on simulator.
Edit: added more detail,
Any help will be highly appreciated.
Thanks
That's likely normal, depending on t itself - what type does it represent ?
By default the managed linker is disabled (Don't link) on the simulator builds. That means every type will be part of the application.
However the default for device builds is Link SDK. This means unused types (found using static analysis) are removed from the application. This allow reducing the size of the application (by not compiling/shipping the whole .NET BCL inside each app).
Static analysis cannot find detect dynamic use of code, e.g. reflection. If your application depends on reflection is needs to preserve the code: using the [Preserve] attribute, an XML file or adding some extra code that will give an hint to the linker to keep the required members.
See documentation for further details.
In addition to the answer from poupou:
If you're stumbling over this question because you have a similar issue with Unity3D then take a look onto this page: https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html
In general that page shows you how to make sure everything is included in IL2CPP builds:
Use [Preserve] keyword on you classes
or
Add a link.xml file into your Assets root

Force USB Thumb Drive to Mount Before Continue

I am writing an updater program on in C# using Visual Studio 2008 on Windows 7. I would like the user to insert a USB thumb drive and if the program finds the drive and updates on the drive then it automatically copies them over. I desire to check only once at startup and then execute a program that is unaware of the updates (updates really need to happen with the program shutdown).
My issue is that the update program is being run before the thumb drive is being mounted so the computer detects no thumb drive and no updates and moves on prematurely. I want to have everything running as fast as possible but I need to force any thumb drives to mount before detection. Everything must be automatic with no input from the user.
Is this possible in c#?
Edit with more detail:
I currently run a batch file at startup (actually as the Windows 7 shell, but I'm not sure that makes a difference). The batch file runs the update check then the actual program. If the user had the USB drive stuck in at boot then I would like the updater to look at the drive and copy over any new files.
The current coded looks like:
DriveInfo[] ListDrives = DriveInfo.GetDrives();
foreach (DriveInfo Drive in ListDrives)
{
if(Drive.DriveType == DriveType.Removable)
{
// double check it's valid and copy over stuff
}
}
but it currently finds no drives at boot. If I run it later then everything is fine. I am assuming that since I run the updater so early it just hasn't had a chance to mount, but I don't just want to wait N seconds if I don't have to because under normal circumstances that's just dead time.
If I can do this check easy up from it is much simpler than having to continually monitor for an event and then shut everything down and do an update.
I would suggest a solution like the following one:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
/// <summary>
/// Represents our program class which contains the entry point of our application.
/// </summary>
public class Program
{
/// <summary>
/// Represents the entry point of our application.
/// </summary>
/// <param name="args">Possibly spcified command line arguments.</param>
public static void Main(string[] args)
{
RemovableDriveWatcher rdw = new RemovableDriveWatcher(); // Create a new instance of the RemoveableDriveWatcher class.
rdw.NewDriveFound += NewDriveFound; // Connect to the "NewDriveFound" event.
rdw.DriveRemoved += DriveRemoved; // Connect to the "DriveRemoved" event.
rdw.Start(); // Start watching.
// Do something here...
Console.ReadLine();
rdw.Stop(); // Stop watching.
}
/// <summary>
/// Is executed when a new drive has been found.
/// </summary>
/// <param name="sender">The sender of this event.</param>
/// <param name="e">The event arguments containing the changed drive.</param>
private static void NewDriveFound(object sender, RemovableDriveWatcherEventArgs e)
{
Console.WriteLine(string.Format("Found a new drive, the name is: {0}", e.ChangedDrive.Name));
}
/// <summary>
/// Is executed when a drive has been removed.
/// </summary>
/// <param name="sender">The sender of this event.</param>
/// <param name="e">The event arguments containing the changed drive.</param>
private static void DriveRemoved(object sender, RemovableDriveWatcherEventArgs e)
{
Console.WriteLine(string.Format("The drive with the name {0} has been removed.", e.ChangedDrive.Name));
}
}
The RemoveableDriveWatcher class looks like this:
/// <summary>
/// Repesents a watcher class for removable drives.
/// </summary>
public class RemovableDriveWatcher
{
/// <summary>
/// Represents the watcher thread which watches for new drives.
/// </summary>
private Thread watcherThread;
/// <summary>
/// Continas all found logical drives of this system.
/// </summary>
private List<DriveInfo> foundDrives;
/// <summary>
/// Initializes a new instance of the <see cref="RemovableDriveWatcher"/> class.
/// </summary>
public RemovableDriveWatcher()
{
this.foundDrives = new List<DriveInfo>();
this.watcherThread = new Thread(new ThreadStart(ScanLogicalDrives));
this.WaitBetweenScansDelay = 1000;
}
/// <summary>
/// Is fired if a new drive has been detected.
/// </summary>
public event EventHandler<RemovableDriveWatcherEventArgs> NewDriveFound;
/// <summary>
/// Is fired if a drive has been removed.
/// </summary>
public event EventHandler<RemovableDriveWatcherEventArgs> DriveRemoved;
/// <summary>
/// Gets or sets the delay in ms between two scans.
/// </summary>
public int WaitBetweenScansDelay
{
get;
set;
}
/// <summary>
/// Starts the watcher.
/// </summary>
public void Start()
{
if (!this.watcherThread.IsAlive)
{
this.watcherThread.Start();
}
}
/// <summary>
/// Stops the watcher.
/// </summary>
public void Stop()
{
if (this.watcherThread.IsAlive)
{
this.watcherThread.Abort();
this.watcherThread.Join();
}
}
/// <summary>
/// Scans for logical drives and fires an event every time a new
/// drive has been found or a drive was removed.
/// </summary>
private void ScanLogicalDrives()
{
DriveInfo[] drives;
do
{
drives = DriveInfo.GetDrives();
// Check for new drives
foreach (DriveInfo drive in drives)
{
if (!(drive.DriveType == DriveType.Removable))
{
continue;
}
if (!drive.IsReady)
{
continue;
}
if (!this.foundDrives.ContainsWithName(drive))
{
this.foundDrives.Add(drive);
if (this.NewDriveFound != null)
{
this.NewDriveFound(this, new RemovableDriveWatcherEventArgs(drives, drive));
}
}
}
// Check for removed drives
for (int i = this.foundDrives.Count - 1; i >= 0; i--)
{
DriveInfo drive = this.foundDrives[i];
if (!drives.ContainsWithName(drive))
{
if (this.DriveRemoved != null)
{
this.DriveRemoved(this, new RemovableDriveWatcherEventArgs(drives, drive));
}
this.foundDrives.RemoveWithName(drive);
}
}
// Sleep
Thread.Sleep(this.WaitBetweenScansDelay);
}
while (true);
}
}
For everything to work you need the RemovableDriveWatcherEventArgs:
/// <summary>
/// Represents the RemovableDriveWatcherEventArgs
/// </summary>
public class RemovableDriveWatcherEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="RemovableDriveWatcherEventArgs"/> class.
/// </summary>
/// <param name="allDrives">All currently available logical drives in the system.</param>
/// <param name="changedDrive">The changed drive.</param>
public RemovableDriveWatcherEventArgs(DriveInfo[] allDrives, DriveInfo changedDrive)
{
this.Drives = allDrives;
this.ChangedDrive = changedDrive;
}
/// <summary>
/// Gets the changed logical drive that has either been detected or removed.
/// </summary>
public DriveInfo ChangedDrive { get; private set; }
/// <summary>
/// Gets all currently available logical drives.
/// </summary>
public DriveInfo[] Drives { get; private set; }
}
And of course the Extensions:
/// <summary>
/// Contains extensions used by the RemovableDriveWatcher class.
/// </summary>
public static class RemovableDriveWatcherExtensions
{
/// <summary>
/// Extends the DiveInfo[] by the ContainsWithName method.
/// </summary>
/// <param name="all">The array where we want to find the specified instance.</param>
/// <param name="search">The instance which we want to find in the array.</param>
/// <returns>TRUE if the specified instance was found, FALSE if the specified instance was not found.</returns>
public static bool ContainsWithName(this DriveInfo[] all, DriveInfo search)
{
for (int i = 0; i < all.Length; i++)
{
if (all[i].Name == search.Name)
{
return true;
}
}
return false;
}
/// <summary>
/// Extends the List<DriveInfo> by the ContainsWithName method.
/// </summary>
/// <param name="all">The array where we want to find the specified instance.</param>
/// <param name="search">The instance which we want to find in the list.</param>
/// <returns>TRUE if the specified instance was found, FALSE if the specified instance was not found.</returns>
public static bool ContainsWithName(this List<DriveInfo> all, DriveInfo search)
{
for (int i = 0; i < all.Count; i++)
{
if (all[i].Name == search.Name)
{
return true;
}
}
return false;
}
/// <summary>
/// Extends the List<DriveInfo> by the RemoveWithName method.
/// </summary>
/// <param name="all">The array where we want to removed the specified instance.</param>
/// <param name="search">The instance which we want to remove in the list.</param>
public static void RemoveWithName(this List<DriveInfo> all, DriveInfo search)
{
for (int i = 0; i < all.Count; i++)
{
if (all[i].Name == search.Name)
{
all.RemoveAt(i);
return;
}
}
}
}
I hope this helps a little bit.
You don't give much detail, but it seems likely you could call DriveInfo.GetDrives() which returns an array of type DriveInfo[]
DriveInfo has an IsReady() method. Presumably once you check that the drive is ready, you can look for a well-known file on the USB drive() to verify they have mounted the correct USB
You could poll in a loop till you find what you want, but if you don't find what you want in say 60 seconds, you will need to notify the user that you can't find the USB drive you need.
I do not see a ready check inside of the if statement. According to MSDN:
IsReady indicates whether a drive is ready. For example, it indicates
whether a CD is in a CD drive or whether a removable storage device is
ready for read/write operations. If you do not test whether a drive is
ready, and it is not ready, querying the drive using DriveInfo will
raise an IOException.
Are you checking for an IOException? I do not see an IsReady event so you may have to spinwait or hook into the lower level Windows API to find an event to indicate drive readiness. Here's an idea for the meantime:
try
{
DriveInfo[] ListDrives = DriveInfo.GetDrives();
foreach (DriveInfo Drive in ListDrives)
{
if(!Drive.IsReady)//spin
if(Drive.DriveType == DriveType.Removable)
{
// double check it's valid and copy over stuff
}
}
}
catch(IOException ex)//...
I don't have any way to test this right now. Please let me know how it works out for you or if there's more details I need to be aware of.
However, because you are starting this process on startup there's always the possibility that IsReady will not be sufficient and once again you may have to find something else (Windows API I imagine). I have not discovered any documentation that say's anything to the effect.

Rhino Mocks : How to change expectation on method, property or field without clear all expectation?

I use Rhino Mocks version 3.6 and the answer that I found here doesn't work in my case :
[TestMethod()]
public void Test()
{
IConnected connectable = MockRepository.GenerateStub<IConnected>();
connectable.Stub(c => c.Connect()).Do(new Action(() =>
{
bool test = false;
if (!test)
test = true;
})).Repeat.Any();
connectable.Stub(c => c.Connect()).Do(new Action(() => { })).Repeat.Any();
}
And I've got an InvalidOperationException: The result for IConnected.Connect(); has already been setup.
I tests it with stub and mock and I've got same results.
I made the same test with property and it doesn't work too.
[TestMethod()]
public void Test()
{
IConnected connectable = MockRepository.GenerateStub<IConnected>();
connectable.Stub(c => c.IsConnected).Return(true).Repeat.Any();
connectable.Stub(c => c.IsConnected).Return(false).Repeat.Any();
}
Is it a bad version of Rhino Mocks or is there a regression ?
The only method that work is to clear all expectation but I must reset to same value all aver expectations :
// clear expectations, an enum defines which
_stubRepository.BackToRecord(BackToRecordOptions.All);
// go to replay again.
_stubRepository.Replay();
My IConnected interface :
/// <summary>
/// Represents connected component management interface.
/// </summary>
public interface IConnected
{
/// <summary>
/// Gets the connection status.
/// </summary>
ConnectionState ConnectionStatus { get; }
/// <summary>
/// Gets a value indicating whether this instance is connected.
/// </summary>
/// <value>
/// <c>true</c> if this instance is connected; otherwise, <c>false</c>.
/// </value>
bool IsConnected { get; }
/// <summary>
/// Occurs when [connection state changed].
/// </summary>
event EventHandler<ConnectionStateChangeEventArgs> ConnectionStateChanged;
/// <summary>
/// Connects this instance.
/// </summary>
void Connect();
/// <summary>
/// Disconnects this instance.
/// </summary>
void Disconnect();
/// <summary>
/// Occurs when [reconnect].
/// </summary>
event EventHandler<ConnectionRetryEventArgs> RetryConnection;
}
You can implement some behavior for stubs via Do() handler.
Here is a solution for your case:
var isConnected = false;
var stub = MockRepository.GenerateStub<IConnected>();
stub
.Stub(c => c.IsConnected)
.Do((Func<bool>)(() => isConnected))
.Return(false);
stub
.Stub(c => c.Connect())
.Do((Action)(() => { isConnected = true; }));
now just test:
Console.WriteLine(stub.IsConnected);
stub.Connect();
Console.WriteLine(stub.IsConnected);
But it would be much better if you redesign your tests to avoid cases when you need such a complex stub (of cource if it is possible). Probably split test into a few more tests might be suitable.

Categories

Resources