Programatically editing a another applications config file from a web service? - c#

I am trying to edit a config file of another application with my Web Service.
Currently I have:
[WebMethod]
public string EditConfig(string path)
{
string cfgPath = Path.Combine(path, "Compressor.exe.config");
var configMap = new ExeConfigurationFileMap { ExeConfigFilename = cfgPath };
var cf = ConfigurationManager.OpenMappedExeConfiguration(configMap,
ConfigurationUserLevel.None);
string hello = cf.AppSettings.Settings["SaveTo"].Value;
return hello;
//cf.AppSettings.Settings["RandomAddedKey"].Value = "Hello World!";
//cf.Save();
}
I have also tried:
var config = ConfigurationManager.OpenExeConfiguration(path);
var hello = config.AppSettings.Settings["SaveTo"].Value;
return hello;
Sadly I haven't had success with any of these, and before resorting to the XML Editor I needed to make sure that this isn't possible or I am doing something wrong?
I have searched through StackOverFlow and the best results returned me an "Object reference not set to an instance of an object." Exception.
I have tried feeding the exe to the path the config and only the directory in several different applications.
In this case I want the Web Service to tell the Compressor what to compress and where to save it, but in the code I am just experimenting to get it working.
I am using .NET Framework 3.5 (Latest for web services).
I have tried editing apps in different kinds of framework versions and the end result was the same.
Thank you in advance.

If I get it right, what you want to do is manipulate a configuration file of another application programmatically. Your problems have nothing to do with doing your manipulation inside a web service application. While I think it is relatively easy to manipulate a configuration file through the very same application, it is not such an easy task to do it from another application. I would suggest two approaches:
Use the .NET API to do it. Here you can find an example of manipulating configuration files remotely.
You could manipulate the specific configuration file, as every other XML file using the respective .NET libraries. Here you can see how to do it.
Hope I helped!

Related

CommonApplicationData folder read-only after using MSIX Packaging Tool

I have written a .Net Windows Forms application that uses the common application data folder to store logfiles and user accounts. The application is distributed using an install shield project and runs perfect on all different Windows versions.
Some parts of the code from different files is shown below
// Defining the path to use (in ProductInfo class)
public static string CommonApplicationDataPath
{
get
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
path = StringHelper.EnsureEndsWithSlash(path);
path += Vendor + #"\" + ProductName + #"\";
return path;
}
}
// Configuring the logger and user manager instances at startup
Logger.Configure(string.Empty, ProductInfo.Password, ProductInfo.CommonApplicationDataPath);
UserManager.Configure(User.Empty, ProductInfo.Password, ProductInfo.CommonApplicationDataPath,
ProductInfo.UserLimitCount);
// Example method for saving the users to file (in UserManager class)
public bool SaveUsers(AppUsers appUsers)
{
AppUsersSerializer serializer = new AppUsersSerializer(_password, _fileName);
if (serializer.Serialize(appUsers) == true)
{
return true;
}
else
{
Logger.Instance.Log(Logs.ErrorB.UserSave, _fileName);
return false;
}
}
I would now like to publish the application via Windows Store and have used the MSIX Packaging Tool. To sign the package I have created a self signed certificate and added it to the Trusted Root Certificate Authorities. The .msix package is install on the same PC as my old desktop version of the app.
The problem I have is that the application is not able to write to the files located in the CommonApplicationData folder. The application can read and load the data, but not update and write the changes to the files. Thus, the path to the files is correct, but some write permission seems to be missing. I have tried different capabilities on the package and even ticked all, but without any effect.
I have also browsed to the C:\Program Files\WindowsApps\<my app package>\ folder and checked the structure of the application and located the files. They are there, but only readable for the app. Removing the files will not create new ones when they should be added as done in the old desktop Windows Forms version.
The application is quite big and contains lots of functionality which runs great in the Windows Store app context. The only missing piece is the above mentioned issues with the file writing.
Any advice would be really appreciated.
After some continued searching on different websites I came across a viable solution for my issue.
The Microsoft MSDN blog described how to use the different folders in an appropriate way.
http://blogs.msdn.microsoft.com/appconsult/2017/03/06/handling-data-in-a-converted-desktop-app-with-the-desktop-bridge/
The proposed solution is to change:
string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
to:
string path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
It will place the files in the user's local directory, meaning the data will be available only for the current user. Sharing the same log file and user accounts between different users of the application, will thus not be possible but that is ok for now.
You may also need to make sure that the folder exists:
C:\Users\<user>\AppData\Local\<vendor>\<product> because it might not always be created during installation of your application. It depends if it has user specific settings or not.
CommonApplicationData folder read-only after using MSIX Packaging Tool
If you have converted your app to store app, we could regard it as UWP app, In general, we store the user info with LocalSettings class that could keep the data during the app updating.
var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
// Create a simple setting.
localSettings.Values["exampleSetting"] = "Hello Windows";
// Read data from a simple setting.
Object value = localSettings.Values["exampleSetting"];
if (value == null)
{
// No data.
}
else
{
// Access data in value.
}
// Delete a simple setting.
localSettings.Values.Remove("exampleSetting");
For more detail, please refer Store and retrieve settings and other app data

ConnectionString in app.config API with ASP.NET

I am currently on a solution in ASP.net containing two project. One MVC project and the other is a class library serving as an API.
Currently I have a connection string like this in the web config of my project MVC.
I read it with the following code in my API:
public ConnectionProvider()
{
this.connectionString = ConfigurationManager.ConnectionStrings[Connection.Name].ConnectionString.ToString();
factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings[Connection.Name].ProviderName.ToString());
}
The problem is that I would like to move the connection string in the app.config of my API and by default but every time it starts, it will read in the web.config.
Using a resource file is a bad idea.
Just copy the the connection string from the api and have it in the web.config. By using the resource file there is no way to update that connection string without having to recompile.
The web application will use web.config and the connection string will be accessible from there. If the same api is to be reused in another project, say a desktop application, again just copy the connection string to the config file of the entry point.
As I suggested via comment, I would use a resource file in the class library.
While #Nkosi is not wrong that the connectionstring will be static, it's the easiest way to carry the connectionstring across w/o having an actual API or database call.
However, it's not the entire application that needs to be republished.
If the functionality in the code of the class library does not change, you can simply build the class library and overwrite the .dll of it.
Another valuable solution would be to save the connectionstring in a separate text file which all solutions will use.
Then you can replace that piece of code in all your applications while having 1 centralized point of access which can be replaced w/o building and replacing anything :).
(Posted solution on behalf of the OP).
Thanks to Dieter B!
With a resource file:
And for read it in the API:
public ConnectionProvider()
{
ResourceManager rm = new ResourceManager("Bank.Project.API.resources", GetAssemblyByName("Bank.Project.API"));
this.connectionString = rm.GetString(Connection.Name);
this.factory = DbProviderFactories.GetFactory(rm.GetString(Connection.Factory));
}
Assembly GetAssemblyByName(string name)
{
var Myassembly = AppDomain.CurrentDomain.GetAssemblies().
SingleOrDefault(assembly => assembly.GetName().Name == name);
return Myassembly;
}

Converting docx to html with dotnet-mammoth fails at deploy server

I'm using dotnet-mammoth (mammoth.js with edge.js) to convert a docx document to html in .net
I added it to my project via its nuget package.
I'm using the code provided by the sample, which is working correctly in my development enviroment (running IIS Express):
var documentConverter = new Mammoth.DocumentConverter();
var result = documentConverter.ConvertToHtml(Server.MapPath("~/files/document.docx")); // problem here at production enviroment
string theResult = result.Value
However, once I deploy it to production server, when the executed code reaches documentConverter.ConvertToHtml() method, it's redirecting me to the login page. Without displaying any error messages, without saving anything on IIS log file.
If I remove that line, everything else executes normally.
I assume it could be an issue related to permissions but I don't know what could it be. Any ideas?
The latest version of Mammoth on NuGet no longer uses edge.js, and is now just .NET code, so should work more reliably.
You can resolve this by getting the exact error when the process is trying to read the file. Below is the code from dotnet-mammoth DocumentConverter.cs. As shown below on call it is trying to read all bytes to be sent to edge
public Result<string> ConvertToHtml(string path)
{
var mammothJs = ReadResource("Mammoth.mammoth.browser.js") + ReadResource("Mammoth.mammoth.edge.js");
var f = Edge.Func(mammothJs);
var result = f(File.ReadAllBytes(path));
Task.WaitAll(result);
return ReadResult(result.Result);
}
I suppose you are giving absolute path to the input. In that case the absolute path should be accessible by app identity hosting the app pool of the web application.
If the path specified is in web root directory - (not advised) - but if it is then you can use Server.MapPath

Use external xml file after publishing the c# desktop application

I have developed a c# desktop application that needs to be hosted on a server and will be scheduled to fetch data based on queries stored in XML files. while developing, I was using the following code to read XML files:
var query = new XPathDocument(#"C:\\Documents and Settings\\XYZ\\Desktop\\productplanningquery.xml");
as you can see I had put the XML file conveniently on my desktop and it worked fine while development. What I want to do now, is to give at a path such that where ever I host the application plus the XML files, it does not throw an exception. One way i thought could be to have a folder in a directory where the application will be installed but for that i will have to figure out the path to current directory dynamically (which i could not figure out).
Please help.
You could pass the location of you XML using args this way you're code would look like so:
var query = new XPathDocument(args[0])
You can also use relative path. Make sure that when deploying your code you keep the location of the file in the same relative location. For example if you place the XML in the same directory as the application
var query = new XPathDocument("productplanningquery.xml")
I am not sure what you want to achieve whether you want to read xml using winform app and do some operation and then pass it web app or some thing else. But here is my understandings:
Case 1: If you need to create XML outside the IIS and that XML will be consumed by ASP.Net app, then :
For using a desktop application with IIS server , you need to have full administrative access to the Live Machine. If its not then you should consider building windows services to operate on the XML files or any task that will run behind the scenes to decrease the load of the asp.net app.
Still in this case if you dont own a server then you need some Virtual Private Hosting or similar kind of hosting where you have almost all previleges to access the system. Then deploy the Windows Service, set the output path in such a manner so that it can be accessed by asp.net app too. And do whatever you want.
Case 2: If you want o read XML in ASP.Net Solely, then
In this case you case read it easily by using XDocument.But note, XML should in the same application directory or under the reach of the ASP.Net app
MSDN Article for Web-Windows Services with ASP.Net
You can use something like this:
var path = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "productplanningquery.xml");
var pathForCurrentApp = string.Format("{0}\\{1}", Environment.CurrentDirectory, "productplanningquery.xml");

Logging to TextFile from SharePoint

I'm trying to debug a webpart installed on a client's SharePoint instance. I wanted a quick and easy logging feature, so I thought of writing messages to a text file in the temp directory. SharePoint doesn't seem to like it, so what are my options?
IF you are writing to the temp directory, you will need to give the file (if it exists) or the directory rights for the IIS Application pool that the SharePoint IIS application is running under.
There are few ways of custom logging in sharepoint -
Use SPDiagnosticsService - You may write to the ULS via SPDiagnosticsService class.
Utilize diagnostics.asmx web service -
SharePointDiagnostics SharePointDiagnosticsObject = new SharePointDiagnostics();
SharePointDiagnosticsObject.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
string Response = SharePointDiagnosticsObject.SendClientScriptErrorReport(message, file, line, client, stack, team, originalFile);
For more details on usage of diagnostics.asmx refer the following link -
https://vivekkumar11432.wordpress.com/2016/09/23/how-to-do-logging-in-uls-from-csom-in-c/
For more details on logging refer the following link -
http://www.codeproject.com/Articles/620996/Five-suggestions-to-implement-a-better-logging-in
Don't use
Microsoft.Office.Server.Diagnostics.PortalLog.LogString("Message");
According to Microsoft documentation - LogString is reserved for internal use and is not intended to be used directly from your code.
I would guess that this is a permissions issue that SharePoint is blocking you on (and probably not telling you that it is). When you try to write to a text file on the server, you need to have elevated permissions in order to do it. You can accomplish this using SPSecurity.RunWithElevatedPrivileges. Something like the following, if you want just a simple, small-code solution.
SPSecurity.RunWithElevatedPrivileges(delegate() {
using (StreamWriter sw = new StreamWriter(#"C:\log.txt"))
{
//log information here
}
});
Try a logging framework like log4net, or write a small logging framework writing into an external database, you could also use lists to log if you want to stay inside sharepoint

Categories

Resources