Parser.Default.ParseArguments always returns false - c#

I have added CommandLineParser library into my project and I have configure all the arguments which should be provided to my project for to support silent installation of the same.
An InstallOptions class is being created with some "Option" attributes for each of the required and non-required arguments to the same e.g. below
public class InstallOptions
{
[Option("path", Required = true, HelpText = "The installation path where you want the application installed.")]
public string InstallPath { get; set; }
[Option("dbname", Required = true, HelpText = "Database name.")]
public string DbName { get; set; }
[Option("dbserver", Required = true, HelpText = "Database server name or IP address.")]
public string DbServer { get; set; }
[HelpOption]
public string DisplayHelpOnParseError()
{
var help = new HelpText()
{
AddDashesToOption = true
};
var errors = "";
if (LastParserState.Errors.Any())
{
errors = help.RenderParsingErrorsText(this, 0);
}
//HACK fix where if help.addoptions is called more than once it truncates the output
if (_help == null)
{
help.AddOptions(this);
_help = help;
}
else
{
return String.IsNullOrEmpty(errors) ? _help : "ERROR(S):" + errors + _help;
}
return help;
}
}
From my program.cs file I want to debug I am running my project as below
public static void Main(string[] args)
{
args = new string[3];
args[0] = "--path C:\\Program files\MyProject";
args[1] = "--dbname myDBName";
args[2] = "--dbserver myDBServer";
var result = Parser.Default.ParseArguments(args, installOptions);
if (!result) throw new ArgumentException(installOptions.DisplayHelpOnParseError());
}
in the above code I all the time getting result = false and states throws below error message
--path required. The installation path where you want the application installed.
--dbname required. Database name.
--dbserver required. Database server name or IP address.
Please help me how to pass all 3 parameter to my project to test it is working correctly.
Thanks in advance

Arguments should be passed as below

Related

Only one of arguments should be allowed with CommandLineParser

Im working on a console tool which accepts some arguments and then parses to the Option class.
What I need is a property that will verify if only one of many marked fields in Option class has values (arguments were delivered).
Ex.
Its ok when we run:
my.exe -a
my.exe -b
but NOT:
my.exe
my.exe -a -b
CommandLine.OptionAttribute cannot do such a thing. What i did is:
Main class args[] got extension .Parse:
args.Parse(options)` //where options is my Options class
inside:
CommandLine.Parser.Default.ParseArguments(args, options);
var isOnlyOneOfMany = options.GetType().GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(OneOfMany)) && prop.GetValue(options) != null).Count() == 1;
how to do this better way?
I will rewrite your Options class
class Options
{
public int OneOfManyCount { get; private set;}
// This is not OneOfMany
[Option('n', "name", Required = true)]
public string Name { get; set; }
private string _Value;
[OneOfMany]
[Option('v', "value", Required = true)]
public string Value { get { return _Value; } set { _Value = value; OneOfManyCount++;} }
private string _Date;
[OneOfMany]
[Option('d', "data", Required = true)]
public string Data { get { return _Date; } set { _Date = value; OneOfManyCount++;} }
}
and in your main, you can call options.OneOfManyCount to get the number of arguments
CommandLine.Parser.Default.ParseArguments(args, options);
if(options.OneOfManyCount != 1) //Do something
And please notice if you have a DefaultValue attribute on one of you OneOfMany, it will hit the set one more time which means OneOfManyCount will have unexpected value.
Update: This solution doesn't work from version 2.8.0 because both SetName and Group are not allowed in option
You can use SetName and GroupName to achieve this behavior:
GroupName: Available from version 2.7+
An option group represents a group of options which are optional, but at least one should be available.
SetName: Available from version 1.9+
It means that you can run commands of one set at a time. You can't mix
commands of more than one set otherwise you get an error.
The new option class:
public class Options
{
[Option('a', "aValue", Group = "Values", SetName = "ASet")]
public bool AValue { get; set; }
[Option('b', "aValue", Group = "Values", SetName = "BSet")]
public bool BValue { get; set; }
}
How to parse the args:
var options = Parser.Default.ParseArguments<Options>(args);

How can I pass a Soap Header to a SOAP WCF Service in Visual Studio?

I'm trying to consume a third-party web service (discription on russian language) https://92.46.122.150:8443/esf-web/ws/SessionService?wsdl
I am trying to connect to a website using method "createSession", get Id session and close session in a website.
Do this I using Visual Studio 2013, C#, .NET 4.5, WSE 3.0 (Microsoft.Web.Services3.dll).
I have already created project in Visual Studio 2013 "Windows Forms Application". In this form user can enter user name, login and to choose his a digital signature certificate. Also I added web service as a "web service reference" but I'm not sure how to pass the credentials for the header.
I'm trying to do this:
string strPasswordCertificate = "123456";
string strCertificate = "C:/Test/AUTH_RSA_db79bb07b4722c042e025979b3b11995fc46765b.p12";
X509Certificate x509_CertAUTH = new X509Certificate(strCertificateFilePathAUTH, strPasswordCertificate);
string strCertAUTH = x509_CertAUTH.ToString();
CreateSessionRequest CreateReq = new CreateSessionRequest();
CreateReq.x509Certificate = strCertAUTH;
string strIIN = "753159846249";
CreateReq.tin = strIIN;
WS.createSession(CreateReq);
But when run a programm Visual studio show an error on a line with "WS.createSession(CreateReq)" like below:
SoapHeaderException was unhandled.
An unhandled exception of type "System.Web.Service.Protocols.SoapHeaderExeption" occurred in System.Web.Services.dll
Additional information: An error was discovered processing the "wsse:Security" header.
This exception is thrown when an XML Web service method is called over SOAP and an exception occurs during processing of the SOAP header.
After that I made changes in my code like below:
string strPasswordCertificate = "123456";
string strCertificate = "C:/Test/AUTH_RSA_db79bb07b4722c042e025979b3b11995fc46765b.p12";
X509Certificate x509_CertAUTH = new X509Certificate(strCertificateFilePathAUTH, strPasswordCertificate);
string strCertAUTH = x509_CertAUTH.ToString();
CreateSessionRequest CreateReq = new CreateSessionRequest();
CreateReq.x509Certificate = strCertAUTH;
string strIIN = "753159846249";
CreateReq.tin = strIIN;
WS.createSession(CreateReq);
string _userName = "123456789011";
string _UserPassword = "TestPass123";
UsernameToken userToken;
userToken = new UsernameToken(_userName, _UserPassword, PasswordOption.SendPlainText);
SessionService WS = new SessionService();
SoapContext requestContext = WS.RequestSoapContext;
requestContext.Security.Tokens.Add(userToken);
WS.createSession(CreateReq);
But when run a programm Visual studio show error on a line with "WS.createSession(CreateReq)" like below:
SoapHeaderException was unhandled.
An unhandled exception of type 'System.Web.Service.Protocols.SoapHeaderExeption' occurred in System.Web.Services.dll
Additional information: An invalid security token was provided.
What I need more to do or change in my code that web reverence start to work? Any idea?
First, need add web service "https://92.46.122.150:8443/esf-web/ws/SessionService?wsdl" like Service Reference.
Second, your certificate should be like trusted. If not, then you can do this using code below:
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Third, add in your solution new item like C# class for your SOAP header. In this class shoud be code like below:
namespace WindowsFormsApplication1
{
public class MySoapSecurityHeader : MessageHeader
{
private readonly UsernameToken _usernameToken;
public MySoapSecurityHeader(string username, string password)
{
_usernameToken = new UsernameToken(string.Empty, username, password);
}
public MySoapSecurityHeader(string id, string username, string password)
{
_usernameToken = new UsernameToken(id, username, password);
}
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
serializer.Serialize(writer, _usernameToken);
}
}
[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
{
public UsernameToken()
{
}
public UsernameToken(string id, string username, string password)
{
Id = id;
Username = username;
Password = new Password() { Value = password };
}
[XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
public string Id { get; set; }
[XmlElement]
public string Username { get; set; }
[XmlElement]
public Password Password { get; set; }
}
public class Password
{
public Password()
{
Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
}
[XmlAttribute]
public string Type { get; set; }
[XmlText]
public string Value { get; set; }
}
}
After that you need add code in a file "Form1.cs":
//The path to the certificate.
string certPath = "C:/AUTH_RSA256_e9f5afab50193175883774ec07bac05cb8c9e2d7.p12";
//Password to signing a certificate
string certPassword = "123456";
//IIN or BIN persom who signing ESF on esf_gov site
var tin = "123456789021";
//Load the certificate into an X509Certificate object.
X509Certificate x509Cert = new X509Certificate(certPath, certPassword);
//Transfer sertificate to string value of base64
var certPEM = ExportToPEM(x509Cert);
using (SessionServiceClient client = new SessionServiceClient())
{
using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(
new MySoapSecurityHeader("123456789011", "TestPass123"));
//Create session for a work with site ESF
CreateSessionRequest createSessionRequest = new CreateSessionRequest
{
tin = tin,
x509Certificate = certPEM
};
var response = client.createSession(createSessionRequest);
MessageBox.Show("Session ID is: " + response.sessionId, "Information message",
MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
//Close session for a work with site ESF
CloseSessionRequest closeSessionRequest = new CloseSessionRequest
{
sessionId = response.sessionId,
tin = tin,
x509Certificate = certPEM
};
var closeResponse = client.closeSession(closeSessionRequest);
}
}
}
public static string ExportToPEM(X509Certificate cert)
{
//Export certificate, get baty array, convert in base64 string
return Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks);
}
Then run a programm and this will be work.

Programatically tell windows firewall to use the Private Network

When I run my c# console app the windows firewall pops up requesting access for vshost32 (my app listens for incomming messages over port 1234 using TCP and UDP). I accept the offered suggestion (private network). The console app then works fine.
I dont want the user to deal with this, so I have added the code below. However when I investigate what this has done in Control Panel > Firewall, it seems to have enabled it for the 'public network' rather than the private network. This is no use as far as allowing my app to work.
Is there an adjustment in the code below to force it to the private network?
INetFwOpenPorts ports3;
INetFwOpenPort port3 = (INetFwOpenPort)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWOpenPort"));
port3.Port = 1234;
port3.Name = "vshost32.exe";
port3.Enabled = true;
//**UPDATE** added for suggestion in answer below - still doesnt change anything though
port3.Scope = NetFwTypeLib.NET_FW_SCOPE_.NET_FW_SCOPE_LOCAL_SUBNET;
Type NetFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
INetFwMgr mgr3 = (INetFwMgr)Activator.CreateInstance(NetFwMgrType);
ports3 = (INetFwOpenPorts)mgr3.LocalPolicy.CurrentProfile.GloballyOpenPorts;
ports3.Add(port3);
INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWRule"));
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallRule.ApplicationName = "<path to your app>";
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
firewallRule.Description = " My Windows Firewall Rule";
firewallRule.Enabled = true;
firewallRule.InterfaceTypes = "All";
firewallRule.Name = "<your rule name>";
// Should really check that rule is not already present before add in
firewallPolicy.Rules.Add(firewallRule);
Refer to my answer to your previous question.
Have a look at the following lines:
private static int Main (string [] args)
{
var application = new NetFwAuthorizedApplication()
{
Name = "MyService",
Enabled = true,
RemoteAddresses = "*",
Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL,
IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY,
ProcessImageFileName = "ServiceAssemblyName.dll",
};
return (FirewallUtilities.AddApplication(application, out exception) ? 0 : -1);
}
The NET_FW_SCOPE_ enumeration has the following values:
NET_FW_SCOPE_ALL = 0,
NET_FW_SCOPE_LOCAL_SUBNET = 1,
NET_FW_SCOPE_CUSTOM = 2,
NET_FW_SCOPE_MAX = 3,
You can further limit the ports, protocol as well as remote addresses to the rule.
UPDATE:
Here is the missing ReleaseComObject function. Place it whatever namespace and remove the reference to ComUtilities.
public static void ReleaseComObject (object o)
{
try
{
if (o != null)
{
if (Marshal.IsComObject(o))
{
Marshal.ReleaseComObject(o);
}
}
}
finally
{
o = null;
}
}
Here is the NetFwAuthorizedApplication class:
namespace MySolution.Configurator.Firewall
{
using System;
using System.Linq;
using NetFwTypeLib;
public sealed class NetFwAuthorizedApplication:
INetFwAuthorizedApplication
{
public string Name { get; set; }
public bool Enabled { get; set; }
public NET_FW_SCOPE_ Scope { get; set; }
public string RemoteAddresses { get; set; }
public string ProcessImageFileName { get; set; }
public NET_FW_IP_VERSION_ IpVersion { get; set; }
public NetFwAuthorizedApplication ()
{
this.Name = "";
this.Enabled = false;
this.RemoteAddresses = "";
this.ProcessImageFileName = "";
this.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
this.IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY;
}
public NetFwAuthorizedApplication (string name, bool enabled, string remoteAddresses, NET_FW_SCOPE_ scope, NET_FW_IP_VERSION_ ipVersion, string processImageFileName)
{
this.Name = name;
this.Scope = scope;
this.Enabled = enabled;
this.IpVersion = ipVersion;
this.RemoteAddresses = remoteAddresses;
this.ProcessImageFileName = processImageFileName;
}
public static NetFwAuthorizedApplication FromINetFwAuthorizedApplication (INetFwAuthorizedApplication application)
{
return (new NetFwAuthorizedApplication(application.Name, application.Enabled, application.RemoteAddresses, application.Scope, application.IpVersion, application.ProcessImageFileName));
}
}
}

Command Line Parser Library .NET being able to retrieve version number

I'm working with the NuGet Command Line Parser Library. I want to be able to set up some command line tools and I want the command(-v or --version) to return the current version of the application. I have another method set up to find the version and set it to a string so all I need now is that command line argument to set to that current version rather than just expecting something after the command. thanks for the help!
static string GetVersion() {
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
string currentVersion = fvi.FileVersion;
return currentVersion;
}
class Options
{
[Option('v', "version", HelpText = "Sets version to be run")]
public string Version { get; set; }
}
that's just the important parts.
Based on the documentation it looks like you want something like this:
// Define a class to receive parsed values
class Options {
[Option('v', "version",
HelpText = "Prints version information to standard output.")]
public bool Version { get; set; }
[ParserState]
public IParserState LastParserState { get; set; }
[HelpOption]
public string GetUsage() {
return HelpText.AutoBuild(this,
(HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current));
}
}
// Consume them
static void Main(string[] args) {
var options = new Options();
if (CommandLine.Parser.Default.ParseArguments(args, options)) {
// Values are available here
if (options.Version) Console.WriteLine("Version: {0}", GetVersion());
}
}
You don't need the Version property to get the version - you can just use it as a "switch" to tell the program to display the version. If you wanted the user to set the version then a get/set string property would be more appropriate.

Programmatically compile typescript in C#?

I'm trying to write a function in C# that takes in a string containing typescript code and returns a string containing JavaScript code. Is there a library function for this?
You can use Process to invoke the compiler, specify --out file.js to a temporary folder and read the contents of the compiled file.
I made a little app to do that:
Usage
TypeScriptCompiler.Compile(#"C:\tmp\test.ts");
To get the JS string
string javascriptSource = File.ReadAllText(#"C:\tmp\test.js");
Full source with example and comments:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
// compiles a TS file
TypeScriptCompiler.Compile(#"C:\tmp\test.ts");
// if no errors were found, read the contents of the compile file
string javascriptSource = File.ReadAllText(#"C:\tmp\test.js");
}
catch (InvalidTypeScriptFileException ex)
{
// there was a compiler error, show the compiler output
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
}
public static class TypeScriptCompiler
{
// helper class to add parameters to the compiler
public class Options
{
private static Options #default;
public static Options Default
{
get
{
if (#default == null)
#default = new Options();
return #default;
}
}
public enum Version
{
ES5,
ES3,
}
public bool EmitComments { get; set; }
public bool GenerateDeclaration { get; set; }
public bool GenerateSourceMaps { get; set; }
public string OutPath { get; set; }
public Version TargetVersion { get; set; }
public Options() { }
public Options(bool emitComments = false
, bool generateDeclaration = false
, bool generateSourceMaps = false
, string outPath = null
, Version targetVersion = Version.ES5)
{
EmitComments = emitComments;
GenerateDeclaration = generateDeclaration;
GenerateSourceMaps = generateSourceMaps;
OutPath = outPath;
TargetVersion = targetVersion;
}
}
public static void Compile(string tsPath, Options options = null)
{
if (options == null)
options = Options.Default;
var d = new Dictionary<string,string>();
if (options.EmitComments)
d.Add("-c", null);
if (options.GenerateDeclaration)
d.Add("-d", null);
if (options.GenerateSourceMaps)
d.Add("--sourcemap", null);
if (!String.IsNullOrEmpty(options.OutPath))
d.Add("--out", options.OutPath);
d.Add("--target", options.TargetVersion.ToString());
// this will invoke `tsc` passing the TS path and other
// parameters defined in Options parameter
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo("tsc", tsPath + " " + String.Join(" ", d.Select(o => o.Key + " " + o.Value)));
// run without showing console windows
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
// redirects the compiler error output, so we can read
// and display errors if any
psi.RedirectStandardError = true;
p.StartInfo = psi;
p.Start();
// reads the error output
var msg = p.StandardError.ReadToEnd();
// make sure it finished executing before proceeding
p.WaitForExit();
// if there were errors, throw an exception
if (!String.IsNullOrEmpty(msg))
throw new InvalidTypeScriptFileException(msg);
}
}
public class InvalidTypeScriptFileException : Exception
{
public InvalidTypeScriptFileException() : base()
{
}
public InvalidTypeScriptFileException(string message) : base(message)
{
}
}
}
Perhaps you could use a JavaScript interpreter like JavaScriptDotNet to run the typescript compiler tsc.js from C#.
Something like:
string tscJs = File.ReadAllText("tsc.js");
using (var context = new JavascriptContext())
{
// Some trivial typescript:
var typescriptSource = "window.alert('hello world!');";
context.SetParameter("typescriptSource", typescriptSource);
context.SetParameter("result", "");
// Build some js to execute:
string script = tscJs + #"
result = TypeScript.compile(""typescriptSource"")";
// Execute the js
context.Run(script);
// Retrieve the result (which should be the compiled JS)
var js = context.GetParameter("result");
Assert.AreEqual(typescriptSource, js);
}
Obviously that code would need some serious work. If this did turn out to be feasible, I'd certainly be interested in the result.
You'd also probably want to modify tsc so that it could operate on strings in memory rather than requiring file IO.
The TypeScript compiler file officially runs on either node.js or Windows Script Host - it is written in TypeScript itself (and transpiled to JavaScript). It requires a script host that can access the file system.
So essentially, you can run TypeScript from any language as long as you can wrap it in a script engine that supports the file system operations required.
If you wanted to compile TypeScript to JavaScript purely in C#, you would end up writing a C# clone of the compiler.

Categories

Resources