Update dynamic Web Reference via command line (wsdl tool) - c#

I have a problem with updating dynamic Web Reference using WSDL.exe tool.
When I'm using "Update Web Reference" in VS, everything is working as expected.
Below is generated code (part of Reference.cs file):
public MyService() {
this.Url = global::ServerReference.Properties.Settings.Default.ServerReference_Reference_MyService;
if ((this.IsLocalFileSystemWebService(this.Url) == true)) {
this.UseDefaultCredentials = true;
this.useDefaultCredentialsSetExplicitly = false;
}
else {
this.useDefaultCredentialsSetExplicitly = true;
}
}
I'm getting necessary information from application properties which are then stored in config file and therefore can be changed without rebuilding application.
However when I use following command:
.\tools\wsdl.exe /l:cs /n:ServerReference /o".\ServerReference\Web References\Reference\Reference.cs" http://localhost:52956/MyService/MyService.asmx
it is created with fixed URL address in Reference.cs file.
Does anybody know how I should change my command to achieve the same Reference.cs file as in Visual Studio?

I don't think you can generate the same code with wsdl.exe.
But if the main thing you want to achieve is generating code that takes the service address from app.config then you can use wsdl.exe with the "/appsettingurlkey" switch.
The code you'll get will be something like this:
public WebService1() {
string urlSetting = System.Configuration.ConfigurationManager.AppSettings["ConfigKeyForServiceUrl"];
if ((urlSetting != null)) {
this.Url = urlSetting;
}
else {
this.Url = "http://localhost:65304/WebService1.asmx";
}
}
Be aware that it reads from 'appSettings' not from 'applicationSettings' through the Settings class, so you'll have to modify your app.config. And it doesn't contain the 'UseDefaultCredentials' stuff either.

Related

SharpShell server .dll NOT signed

I need to develop a Shell Context Menu extension that references some other custom assemblies... I don't want to assign a Strong Name Key to those custom assemblies!
The guide I followed to do this uses the SharpShell project and illustrates how to sign (but does not expalins why) the assembly... and this is my problem: if I sign my final .dll then I have many errors during my project's building phase, because some assemblies my project references are not strongly named ("Referenced assembly does not have a strong name").
In general, googling about the C# Shell Extension implementation, all best tutorials I found sign the final assembly... is it mandatory?
Without signing the assembly ServerManager.exe returns this error: "The file 'XYZ.dll' is not a SharpShell Server".
Finally I've solved my troubles... the SharpShell.dll file obtained through NuGet was a different version of the ServerManager.exe ones.
Uninstalling the SharpShell NuGet package and directly referencing the SharpShell.dll you find inside the ServerManager folder was my solution!
Moreover, I was looking between the article comments... please read this question.
You don't need to use old DLL.
Please use this code directly, without using ServerManager.exe.
private static ServerEntry serverEntry = null;
public static ServerEntry SelectedServerEntry
{
get
{
if (serverEntry == null)
serverEntry = ServerManagerApi.LoadServer("xxx.dll");
return serverEntry;
}
}
public static ServerEntry LoadServer(string path)
{
try
{
// Create a server entry for the server.
var serverEntry = new ServerEntry();
// Set the data.
serverEntry.ServerName = Path.GetFileNameWithoutExtension(path);
serverEntry.ServerPath = path;
// Create an assembly catalog for the assembly and a container from it.
var catalog = new AssemblyCatalog(Path.GetFullPath(path));
var container = new CompositionContainer(catalog);
// Get the exported server.
var server = container.GetExport<ISharpShellServer>().Value;
serverEntry.ServerType = server.ServerType;
serverEntry.ClassId = server.GetType().GUID;
serverEntry.Server = server;
return serverEntry;
}
catch (Exception)
{
// It's almost certainly not a COM server.
MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning");
return null;
}
}
Install code:
ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true);
Register code:
ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit);

ServerManager.CommitChanges( ) throws Error: "Cannot write configuration file"

Here is my code to create an application
public static bool CreateApplication(String websiteName, String applicationName, String AppDIR,String appPoolName)
{
try
{
var windowsDir = Environment.GetEnvironmentVariable("SystemRoot");
Process.Start(windowsDir+#"\system32\inetsrv\appcmd","unlock config -section:system.webServer/security/authentication/windowsAuthentication");
Process.Start(windowsDir+#"\system32\inetsrv\appcmd","unlock config -section:system.webServer/security/authentication/anonymousAuthentication");
ServerManager iisManager = new ServerManager();
if (!applicationName.Contains("/"))
applicationName = "/" + applicationName;
var app = iisManager.Sites[websiteName].Applications.Add(applicationName, AppDIR);
app.ApplicationPoolName = appPoolName;
var config = app.GetWebConfiguration();
var anonsection = config.GetSection("system.webServer/security/authentication/anonymousAuthentication", iisManager.Sites[websiteName].Name + applicationName);
anonsection["enabled"] = false;
var winsection = config.GetSection("system.webServer/security/authentication/windowsAuthentication", iisManager.Sites[websiteName].Name + applicationName);
winsection["enabled"] = true;
iisManager.CommitChanges(); //Blows up here
return true;
}
catch
{
return false;
}
}
Everything is fine until it hit's the commit changes method call.
It throws this error
Error: Cannot write configuration file
All of the code is verified as working except for where I change the enabled values to false and true.
When I added these in it started to explode.
Is there any way to fix this from code, that can be distributed to other machines?
Update:
After re-locking the files
like this
Process.Start(windowsDir + #"\system32\inetsrv\appcmd", "lock config -section:system.webServer/security/authentication/windowsAuthentication");
Process.Start(windowsDir + #"\system32\inetsrv\appcmd", "lock config -section:system.webServer/security/authentication/anonymousAuthentication");
I now get this error
Error: Cannot commit configuration changes because the file has
changed on disk
I also ran into the second of your two issues (Error: Cannot commit configuration changes because the file has changed on disk) for our c# application which we use to configure IIS servers as part of our deploy operation.
For me in the end it was unintentionally nesting two using statements wrapped around the ServerManager object that caused the problem.
For your particular situation I would try to add a using statement for your reference to ServerManager and ensure that the command line appcmd calls are outside the using statement or moved within the using statement but translated into API calls via the ServerManager object.

Set Script Task code dynamically in SSIS 2012

In my application, a script task is created dynamically.
In SQL Server 2008's implementation of SSIS, the following method worked fine.
private void SetSourceCode(ScriptTask scriptTask, string code, string codeName)
{
string fileName = "ScriptMain.vb";
string language = "VisualBasic";
string proj = ".vbproj";
scriptTask.ScriptLanguage = VSTAScriptLanguages.GetDisplayName(language);
scriptTask.ScriptingEngine.InitNewScript(language,
scriptTask.ScriptProjectName, proj);
scriptTask.ScriptingEngine.ShowDesigner(false);
scriptTask.ScriptingEngine.AddCodeFile(fileName, code);
if (!scriptTask.ScriptingEngine.Build())
throw new Exception("Failed to build vb script code: " + codeName);
scriptTask.ScriptingEngine.SaveScriptToStorage();
if (!scriptTask.ScriptingEngine.CloseIDE(false))
{
throw new Exception("Unable to close Scripting engine.");
}
}
How do I migrate this code to SQL Server 2012, because following methods are removed from SQL Server 2012 dll-s (assemblies):
InitNewScript
AddProjectReference
AddCodeFile
SaveScriptToStorage
CloseIDE
Build
ShowDesigner
Generally, how do I dynamically set source code for script task in SQL Server 2012?
As you've noticed, the VSTA helper methods you could use in 2008 were moved/removed in 2012. It is still possible to do, but the code has changed.
The easiest thing to do is load an existing project using VstaHelper.LoadProjectFromFolder().
If you want to dynamically add script files, see the snippet below. There are two main things you need to keep in mind:
The ScriptingEngine and VstaHelper classes represent VSTA itself. This is where you’d create the project, and add new files. You cannot remove or replace an existing file directly here. When you call SaveProjecToStorage(), it's like closing the VSTA window … it saves the project and compiled binary to the ScriptTask.
ScriptTask.ScriptStorage allows you to directly manipulate the source file contents. From here, you can modify the content of a file.
The following code snippet should help you get started.
static void Main(string[] args)
{
// 1. Create new package, and add a script task
var pkg = new Package();
var exec = pkg.Executables.Add("STOCK:ScriptTask");
var th = (TaskHost)exec;
th.Name = "Script Task";
th.Description = "This is a Script Task";
var task = (ScriptTask)th.InnerObject;
// 2. Set the script language - "CSharp" or "VisualBasic"
task.ScriptLanguage = VSTAScriptLanguages.GetDisplayName("CSharp");
// 3. Set any variables used by the script
//task.ReadWriteVariables = "User::Var1, User::Var2";
// 4. Create a new project from the template located in the default path
task.ScriptingEngine.VstaHelper.LoadNewProject(task.ProjectTemplatePath, null, "MyScriptProject");
// 5. Initialize the designer project, add a new code file, and build
//task.ScriptingEngine.VstaHelper.Initalize("", true);
//task.ScriptingEngine.VstaHelper.AddFileToProject("XX.cs", "FileContents");
//task.ScriptingEngine.VstaHelper.Build("");
// 6. Persist the VSTA project + binary to the task
if (!task.ScriptingEngine.SaveProjectToStorage())
{
throw new Exception("Save failed");
}
// 7. Use the following code to replace the ScriptMain contents
var contents = File.ReadAllText("path to file");
var scriptFile =
task.ScriptStorage.ScriptFiles["ScriptMain.cs"] =
new VSTAScriptProjectStorage.VSTAScriptFile(VSTAScriptProjectStorage.Encoding.UTF8, contents);
// 8. Reload the script project, build and save
task.ScriptingEngine.LoadProjectFromStorage();
task.ScriptingEngine.VstaHelper.Build("");
// 9. Persist the VSTA project + binary to the task
if (!task.ScriptingEngine.SaveProjectToStorage())
{
throw new Exception("Save failed");
}
// 10. Cleanup
task.ScriptingEngine.DisposeVstaHelper();
// 11. Save
string xml;
pkg.SaveToXML(out xml, null);
File.WriteAllText(#"c:\temp\package.dtsx", xml);
}

Simple ASMX WebService and DLL not loaded

I've a problem running an ASMX Web Service. I'm Calling a DLL from a method (AceptaTools.dll) and this DLL load ca4xml.dll.
AceptaTools.dll has been registered with REGSVR32. But ca4xml.dll Can't.
When i Invoke the service:
_objURL = _CA4XML.GetLastResponse();
i get a message "ca4xml.dll not loaded".
Looking al Dependency Walker:
Here both files in detail:
Both DLL are in BIN folder and my project run as x86... Why can't load?? Please help.
[WebMethod]
public string Send(string Ip, string Puerto, string NroDocumento, string TipoDocumento, string Comando, string Impresora, string Linea)
{
try
{
int _Result = 0;
string _Null = "";
string _objURL;
//Config Capsula
string serverConfig = "cfg|" + Ip.ToString() + "|" + Puerto.ToString() + "|10";
//Impresora FACTURA,1 por Defecto.
if (string.IsNullOrEmpty(Impresora)) { Impresora = "FACTURA,1"; }
if (string.IsNullOrEmpty(NroDocumento)) { NroDocumento = "0"; }
if (string.IsNullOrEmpty(Comando)) { Comando = "generar"; }
//Nuevo CAXML Cliente
AceptaTools.CA4XML_Client _CA4XML = new CA4XML_Client();
_Result = _CA4XML.Send(ref serverConfig, ref NroDocumento, ref Comando, ref Impresora, ref Linea, out _Null);
if (_Result != 0)
{
_objURL = _CA4XML.GetLastResponse(); //Get URL
return _objURL.ToString();
}
else
{
return "Error";
}
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
}
Did you make sure that the ca4xml.dll is deployed properly? Since I guess it is not referenced as .NET assembly the VS will treat it like a normal file and you will need to specifically tell VS to include it when deploying.
Do the following steps to check whether deployment has been setup properly:
Open the Solution Explorer -> Got to the ca4xml.dll -> Right click -> Select Properties -> Set Build Action = None & Copy to Output = Always
Also in addition to the Dependency Walker I suggest to use Process Monitor. When you use the file access view (disregarding registry changes etc.) you can see all the locations where a process tries to load a dll from. Afterwards you can make sure that the dll you are missing is in one of the listed locations, here is the link:
http://technet.microsoft.com/en-us/sysinternals/bb896645
When you do not load DLL in the program because you need to update some things .
you can update project in nuget manager

Windows service - how to make name configurable

I have written a windows service in C#. The requirement at the beginning was that I should be running only one instance of that service, but that has changed and now I need multiple instances. This is why I need to change the service name according to the configuration file.
What would be the best way to make it register with the correct name ? Should I write another tool to do it? Can I just read the name from App.config file and set it in the service and installer classes accordingly ?
PS> I do not really understand how that thing with names work - one should set names in service and installer classes, but then when installing with installutil.exe or even powershell new-service the name also should be specified. Does that have to be the same? Or one overrides another?
You can simply read it from the app.config and set it in the installer classes.
Normally, a class that inherits from Installer is automatically created. It contains a member of type System.ServiceProcess.ServiceInstaller, most likely named serviceProcessInstaller1. This has a property ServiceName you can set. Additionally, you need to set the ServiceName property of the ServiceBase derived class to the same value.
In a default implementation, these are set to constant values in the respective InitializeComponent methods, but there is no reason to stick with this. It can be done dynamically without problems.
I though I'd add my 2 cents since I ran into this. I have a file called "ProjectInstaller.cs" with designer and resources under it. Opening it up in design shows MyServiceInstaller and MyProjectInstaller as items on the design surface. I was able to change the names in the ProjectInstaller() constructor, and manually loaded the config file from the module directory:
public ProjectInstaller()
{
InitializeComponent();
var config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
if (config.AppSettings.Settings["ServiceName"] != null)
{
this.MyServiceInstaller.ServiceName = config.AppSettings.Settings["ServiceName"].Value;
}
if (config.AppSettings.Settings["DisplayName"] != null)
{
this.MyServiceInstaller.DisplayName = config.AppSettings.Settings["DisplayName"].Value;
}
}
In the same vein as Jason Goemaat's answer, this is how you would loop through all available installers in your project, which saves you the time of being sure you added each new service to this class. In my project, I have a total of 12 services (and we add a new one here and there), and we wanted them grouped together by the instance name, so SVC (Instance 1) Service XX and SVC (Instance 1) Service YY were next to each other when viewed in the services snap-in console.
public ProjectInstaller()
{
InitializeComponent();
var config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
string instanceName = config.AppSettings.Settings["Installer_NamedInstanceName"].Value;
string instanceID = config.AppSettings.Settings["Installer_NamedInstanceID"].Value;
bool usesNamedInstance = !string.IsNullOrWhiteSpace(instanceName) && !string.IsNullOrWhiteSpace(instanceID);
if (usesNamedInstance)
{
foreach (var installer in this.Installers)
{
if (installer is ServiceInstaller)
{
var ins = (ServiceInstaller)installer;
ins.ServiceName = ins.ServiceName + "-" + instanceID;
// Want the service to be named SVC (Instance Name) Audit Log Blah Blah Service
ins.DisplayName = ins.DisplayName.Replace("SVC ", "SVC (" + instanceName + ") ");
}
}
}
}
HOWEVER, there is something else that you need to do - When initializing the service, you must also change the service name, otherwise you'll get an error along the lines of "The executable doesn't implement the service". I did this by implementing the following code in Program.cs:
internal static void HandleCustomServiceName(ServiceBase sbase)
{
if (!string.IsNullOrWhiteSpace(customInstanceName))
{
sbase.ServiceName = sbase.ServiceName + "-" + customInstanceName;
}
}
Then, in the constructor of each service:
public SystemEventWatcher()
{
InitializeComponent();
Program.HandleCustomServiceName(this);
}
I've upvoted Jason's answer for paving the way to implementing this in my own project. Thanks!

Categories