Cloudinary destroy method not working in .Net - c#

I'm currently building an ASP.NET Core 5 MVC for my course. I'm using Cloudinary for storing files in the cloud so I can get bonus points, but I have a problem with deleting files from it. In the documentation is written that I should use DeletionParams class and pass the publicId which I'm storing in the database, but whatever I do the DeletionParams class is returning me "not found".
public void DeleteFile(string publicId)
{
var deletionParams = new DeletionParams(publicId)
{
ResourceType = ResourceType.Raw
};
var results = cloudinary.Destroy(deletionParams);
;
}
And this is what parameters I pass to it
And this is the result from cloudinary
If more information is needed just ask in the comment section.

I found what was the problem. When you want to delete an image you should provide folder and publidId and also ResourceType = ResourceType.Image. If you want to delete a video it's the same way the only thing you should change is ResourceType to ResourceType.Video. For any kinds of other files you should provide full path plus public id and also the file extension and ResoureType should be ResourceType.Raw

Related

Best practice for saving Persistent Settings in C# [duplicate]

What I want to achieve is very simple: I have a Windows Forms (.NET 3.5) application that uses a path for reading information. This path can be modified by the user, by using the options form I provide.
Now, I want to save the path value to a file for later use. This would be one of the many settings saved to this file. This file would sit directly in the application folder.
I understand three options are available:
ConfigurationSettings file (appname.exe.config)
Registry
Custom XML file
I read that the .NET configuration file is not foreseen for saving values back to it. As for the registry, I would like to get as far away from it as possible.
Does this mean that I should use a custom XML file to save configuration settings?
If so, I would like to see code example of that (C#).
I have seen other discussions on this subject, but it is still not clear to me.
If you work with Visual Studio then it is pretty easy to get persistable settings. Right click on the project in Solution Explorer and choose Properties. Select the Settings tab and click on the hyperlink if settings doesn't exist.
Use the Settings tab to create application settings. Visual Studio creates the files Settings.settings and Settings.Designer.settings that contain the singleton class Settings inherited from ApplicationSettingsBase. You can access this class from your code to read/write application settings:
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
This technique is applicable both for console, Windows Forms, and other project types.
Note that you need to set the scope property of your settings. If you select Application scope then Settings.Default.<your property> will be read-only.
Reference: How To: Write User Settings at Run Time with C# - Microsoft Docs
If you are planning on saving to a file within the same directory as your executable, here's a nice solution that uses the JSON format:
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
The registry is a no-go. You're not sure whether the user which uses your application, has sufficient rights to write to the registry.
You can use the app.config file to save application-level settings (that are the same for each user who uses your application).
I would store user-specific settings in an XML file, which would be saved in Isolated Storage or in the SpecialFolder.ApplicationData directory.
Next to that, as from .NET 2.0, it is possible to store values back to the app.config file.
The ApplicationSettings class doesn't support saving settings to the app.config file. That's very much by design; applications that run with a properly secured user account (think Vista UAC) do not have write access to the program's installation folder.
You can fight the system with the ConfigurationManager class. But the trivial workaround is to go into the Settings designer and change the setting's scope to User. If that causes hardships (say, the setting is relevant to every user), you should put your Options feature in a separate program so you can ask for the privilege elevation prompt. Or forego using a setting.
I wanted to share a library I've built for this. It's a tiny library, but a big improvement (IMHO) over .settings files.
The library is called Jot (GitHub). Here is an old The Code Project article I wrote about it.
Here's how you'd use it to keep track of a window's size and location:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
The benefit compared to .settings files: There's considerably less code, and it's a lot less error-prone since you only need to mention each property once.
With a settings files you need to mention each property five times: once when you explicitly create the property and an additional four times in the code that copies the values back and forth.
Storage, serialization, etc. are completely configurable. When the target objects are created by an IoC container, you can [hook it up][] so that it applies tracking automatically to all objects it resolves, so that all you need to do to make a property persistent is slap a [Trackable] attribute on it.
It's highly configurable, and you can configure:
- when data is persisted and applied globally or for each tracked object
- how it's serialized
- where it's stored (e.g. file, database, online, isolated storage, registry)
- rules that can cancel applying/persisting data for a property
Trust me, the library is top notch!
The registry/configurationSettings/XML argument still seems very active. I've used them all, as the technology has progressed, but my favourite is based on Threed's system combined with Isolated Storage.
The following sample allows storage of an objects named properties to a file in isolated storage. Such as:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
Properties may be recovered using:
AppSettings.Load(myobject, "myFile.jsn");
It is just a sample, not suggestive of best practices.
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
A simple way is to use a configuration data object, save it as an XML file with the name of the application in the local Folder and on startup read it back.
Here is an example to store the position and size of a form.
The configuration dataobject is strongly typed and easy to use:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
A manager class for saving and loading:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
Now you can create an instance and use in your form's load and close events:
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
And the produced XML file is also readable:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
Yes, it is possible to save the configuration - but it pretty much depends on the way you choose to do it. Let me describe the technical differences so you can understand the options you have:
First, you need to distinguish, whether you want to use applicationSettings or AppSettings in your *.exe.config(aka App.config in Visual Studio) file - there are fundamental differences, being described here.
Both provide different ways of saving changes:
The AppSettings allow you to read and write directly into the config file via config.Save(ConfigurationSaveMode.Modified);, where config is defined as: config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
The applicationSettings allow to read, but if you write changes (via Properties.Settings.Default.Save();) it will be written on a per-user basis, stored in a special place (e.g. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). As Hans Passant mentioned in his answer, this is because a user usually has restricted rights to Program Files and cannot write to it without invoking the UAC prompt. A disadvantage is if you're adding configuration keys in the future you need to synchronize them with every user profile.
But there are a couple of other alternative options:
Since .NET Core (and .NET 5 and 6) a 3rd option is the appsettings.json file which uses Microsoft's configuration abstraction (and also the secrets.json file which is stored in your user profile rather than in the assemblies directories). But usually WinForms isn't using it, so I am mentioning it just for completeness. However, here are some references how to read and write the values. Alternatively you can use Newtonsoft JSON to read and write the appsettings.json file, but it is not limited to that: you can also create your own json files with that method.
As mentioned in the question, there is a 4th option: If you treat the configuration file as XML document, you can load, modify and save it by using the System.Xml.Linq.XDocument class. It is not required to use a custom XML file, you can read the existing config file; for querying elements, you can even use Linq queries. I have given an example here, check out the function GetApplicationSetting there in the answer.
A 5th option is to store settings in the registry. How you can do it is described here.
Last not least, there is a 6th option: You can store values in the environment (system environment or environment of your account). In Windows settings (the cogwheel in the Windows menu), type in "environment" in the search bar and add or edit them there. To read them, use var myValue = Environment.GetEnvironmentVariable("MyVariable");. Note that your application usually needs to be restarted to get the updated environment settings.
If you require encryption to protect your values, check out this answer. It describes how to use Microsoft's DPAPI to store values encrypted.
And if you want to support your own files, whether XML or JSON, it might be useful to know the directory of the assembly running:
var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);
You can use assemblyDirectory as base directory to store your files.
I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.
"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.
For instance, if a configuration file is like that
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
We can retrieve values like this
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
It is compatible with .NET 2.0 and higher. We can create configuration files on the fly and we can save it later.
Source: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig
Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.
If you use .NET 4.0 dynamic, this library is really easy to use
(serialize, deserialize, nested objects support and ordering output
as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
For .NET YAML configuration library... I haven't found one that is as
easy to use as JsonConfig
You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)
Sample for getting path of special folder: C# getting the path of
%AppData%
If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.
As far as I can tell, .NET does support persisting settings using the built-in application settings facility:
The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving.
- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.
I can imagine two good options:
The strongly typed version and
The object oriented version.
The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.
With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.
You can find the code of both fully functional implementations HERE.
public static class SettingsExtensions
{
public static bool TryGetValue<T>(this Settings settings, string key, out T value)
{
if (settings.Properties[key] != null)
{
value = (T) settings[key];
return true;
}
value = default(T);
return false;
}
public static bool ContainsKey(this Settings settings, string key)
{
return settings.Properties[key] != null;
}
public static void SetValue<T>(this Settings settings, string key, T value)
{
if (settings.Properties[key] == null)
{
var p = new SettingsProperty(key)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
var v = new SettingsPropertyValue(p);
settings.Properties.Add(p);
settings.Reload();
}
settings[key] = value;
settings.Save();
}
}

how saving List<object> to settings in C# uwp

how I can saving List to settings in C# uwp?
define class for object
//class
public class ListOfFile
{
public string File_DisplayName { get; set; }
public string File_Name { get; set; }
public string File_path { get; set; }
public string File_Extension { get; set; }
public StorageFile File_Storage { get; set; }
public ImageSource File_Thumbnail { get; set; }
}
define method For loadfile
Method:
//method
void loadfile()
{
List<ListOfFile> FileBind=new List<ListOfFile>();
var FilesInFolder = await FolderItem.GetFilesAsync();
foreach(var FileItem in FilesInFolder)
{
FileBind.Add(new ListOfFile()
{
File_DisplayName = FileItem.DisplayName,
File_Extension = FileItem.FileType
,
File_Name = FileItem.Name
,
File_path = FileItem.Path
,
File_Thumbnail = bitmapimage
,
File_Storage =FileItem
});
}
ApplicationData.Current.LocalSettings.Values["allfiles"]=FileBind;
}
end line Error :(
how I can saveing list in Settings?
help me please.
UWP Community Toolkit - Object Storage
I know this is over half a year since the original question was asked, but I wish I had found out about the UWP toolkit sooner, as I had a similar situation where I wanted to quickly and easily store a simple class list of device information to roam in roaming settings. Posting this here in case it might be use to someone else in a similar situation like the OP and myself.
If your application targets Windows 10 Build 10586 or higher, you can use the Object Storage helpers that are part of the UWP Community Toolkit by Microsoft to store small or large objects, which also includes Lists.
You can add the toolkit by adding the Microsoft.Toolkit.Uwp NuGet package to your UWP project.
Example for LocalObjectStorageHelper (Snippet Source)
var helper = new LocalObjectStorageHelper();
// Read simple objects
string keySimpleObject = "simple";
if (helper.KeyExists(keySimpleObject))
{
string result = helper.Read<string>(keySimpleObject);
}
// Save simple objects
helper.Save(keySimpleObject, 47);
// Read complex/large objects
string keyLargeObject = "large";
if (await helper.FileExistsAsync(keyLargeObject))
{
var result = await helper.ReadFileAsync<MyLargeObject>(keyLargeObject);
}
// Save complex/large objects
var o = new MyLargeObject
{
...
};
await helper.SaveFileAsync(keySimpleObject, o);
Same can be done with RoamingObjectStorageHelper.
Important Notes
You can save both simple and complex objects like lists using Save(key, object) and SaveFileAsync(key, object).
Save will store the object in local/roaming settings (depending on the storage helper you pick); This means it is subject to data constraints and the total serialized object size must be less than 8 KB.
SaveFileAsync will store the object as a serialized file in the LocalState or RoamingState directories of your app (at least, I believe so) to be accessed later using ReadFileAsync. Use this if your object is very complex and you expect might serialize into a size greater than 8 KB.
Important Caveat
Be careful when storing large/complex objects or list of objects using SaveFileAsync. Each UWP app is only allotted 100 KB (AKA the RoamingStorageQuota). If the quota is exceeded, data replication will cease.
Don't forget that ApplicationData.LocalSettings has limitations.
Each setting can be up to 8K bytes in size.
You are trying to store
List<T>
in settings.
Take a look at supported types
List<T>
is missing there. Looks like you can't do it this way. There is might be only with some converting to object
Take a look at solution on this similar topic:
How to store a list of objects in application settings
UPDATE:
You can try replace BinaryFormatter with DataContractSerializer.
Here is nice article that might help you: Saving and Loading App Data (Windows Store C# UWP / 8.1)
You should not be storing entire files and bitmap images to settings. That is not the correct use of an app's settings feature. At the most, you can store a list of files and their paths, which may allow you to read the contents and display a thumbnail at run-time. If you had mentioned exactly what it is you're trying to achieve, then maybe we could help you a little better.
If you absolutely need to store entire files within your app, you can either copy those files into your app's local storage folder or you can look into integrating with OneDrive for a more portable solution.

How do I add appSettings from C# code? [duplicate]

What I want to achieve is very simple: I have a Windows Forms (.NET 3.5) application that uses a path for reading information. This path can be modified by the user, by using the options form I provide.
Now, I want to save the path value to a file for later use. This would be one of the many settings saved to this file. This file would sit directly in the application folder.
I understand three options are available:
ConfigurationSettings file (appname.exe.config)
Registry
Custom XML file
I read that the .NET configuration file is not foreseen for saving values back to it. As for the registry, I would like to get as far away from it as possible.
Does this mean that I should use a custom XML file to save configuration settings?
If so, I would like to see code example of that (C#).
I have seen other discussions on this subject, but it is still not clear to me.
If you work with Visual Studio then it is pretty easy to get persistable settings. Right click on the project in Solution Explorer and choose Properties. Select the Settings tab and click on the hyperlink if settings doesn't exist.
Use the Settings tab to create application settings. Visual Studio creates the files Settings.settings and Settings.Designer.settings that contain the singleton class Settings inherited from ApplicationSettingsBase. You can access this class from your code to read/write application settings:
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
This technique is applicable both for console, Windows Forms, and other project types.
Note that you need to set the scope property of your settings. If you select Application scope then Settings.Default.<your property> will be read-only.
Reference: How To: Write User Settings at Run Time with C# - Microsoft Docs
If you are planning on saving to a file within the same directory as your executable, here's a nice solution that uses the JSON format:
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
The registry is a no-go. You're not sure whether the user which uses your application, has sufficient rights to write to the registry.
You can use the app.config file to save application-level settings (that are the same for each user who uses your application).
I would store user-specific settings in an XML file, which would be saved in Isolated Storage or in the SpecialFolder.ApplicationData directory.
Next to that, as from .NET 2.0, it is possible to store values back to the app.config file.
The ApplicationSettings class doesn't support saving settings to the app.config file. That's very much by design; applications that run with a properly secured user account (think Vista UAC) do not have write access to the program's installation folder.
You can fight the system with the ConfigurationManager class. But the trivial workaround is to go into the Settings designer and change the setting's scope to User. If that causes hardships (say, the setting is relevant to every user), you should put your Options feature in a separate program so you can ask for the privilege elevation prompt. Or forego using a setting.
I wanted to share a library I've built for this. It's a tiny library, but a big improvement (IMHO) over .settings files.
The library is called Jot (GitHub). Here is an old The Code Project article I wrote about it.
Here's how you'd use it to keep track of a window's size and location:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
The benefit compared to .settings files: There's considerably less code, and it's a lot less error-prone since you only need to mention each property once.
With a settings files you need to mention each property five times: once when you explicitly create the property and an additional four times in the code that copies the values back and forth.
Storage, serialization, etc. are completely configurable. When the target objects are created by an IoC container, you can [hook it up][] so that it applies tracking automatically to all objects it resolves, so that all you need to do to make a property persistent is slap a [Trackable] attribute on it.
It's highly configurable, and you can configure:
- when data is persisted and applied globally or for each tracked object
- how it's serialized
- where it's stored (e.g. file, database, online, isolated storage, registry)
- rules that can cancel applying/persisting data for a property
Trust me, the library is top notch!
The registry/configurationSettings/XML argument still seems very active. I've used them all, as the technology has progressed, but my favourite is based on Threed's system combined with Isolated Storage.
The following sample allows storage of an objects named properties to a file in isolated storage. Such as:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
Properties may be recovered using:
AppSettings.Load(myobject, "myFile.jsn");
It is just a sample, not suggestive of best practices.
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
A simple way is to use a configuration data object, save it as an XML file with the name of the application in the local Folder and on startup read it back.
Here is an example to store the position and size of a form.
The configuration dataobject is strongly typed and easy to use:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
A manager class for saving and loading:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
Now you can create an instance and use in your form's load and close events:
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
And the produced XML file is also readable:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
Yes, it is possible to save the configuration - but it pretty much depends on the way you choose to do it. Let me describe the technical differences so you can understand the options you have:
First, you need to distinguish, whether you want to use applicationSettings or AppSettings in your *.exe.config(aka App.config in Visual Studio) file - there are fundamental differences, being described here.
Both provide different ways of saving changes:
The AppSettings allow you to read and write directly into the config file via config.Save(ConfigurationSaveMode.Modified);, where config is defined as: config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
The applicationSettings allow to read, but if you write changes (via Properties.Settings.Default.Save();) it will be written on a per-user basis, stored in a special place (e.g. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). As Hans Passant mentioned in his answer, this is because a user usually has restricted rights to Program Files and cannot write to it without invoking the UAC prompt. A disadvantage is if you're adding configuration keys in the future you need to synchronize them with every user profile.
But there are a couple of other alternative options:
Since .NET Core (and .NET 5 and 6) a 3rd option is the appsettings.json file which uses Microsoft's configuration abstraction (and also the secrets.json file which is stored in your user profile rather than in the assemblies directories). But usually WinForms isn't using it, so I am mentioning it just for completeness. However, here are some references how to read and write the values. Alternatively you can use Newtonsoft JSON to read and write the appsettings.json file, but it is not limited to that: you can also create your own json files with that method.
As mentioned in the question, there is a 4th option: If you treat the configuration file as XML document, you can load, modify and save it by using the System.Xml.Linq.XDocument class. It is not required to use a custom XML file, you can read the existing config file; for querying elements, you can even use Linq queries. I have given an example here, check out the function GetApplicationSetting there in the answer.
A 5th option is to store settings in the registry. How you can do it is described here.
Last not least, there is a 6th option: You can store values in the environment (system environment or environment of your account). In Windows settings (the cogwheel in the Windows menu), type in "environment" in the search bar and add or edit them there. To read them, use var myValue = Environment.GetEnvironmentVariable("MyVariable");. Note that your application usually needs to be restarted to get the updated environment settings.
If you require encryption to protect your values, check out this answer. It describes how to use Microsoft's DPAPI to store values encrypted.
And if you want to support your own files, whether XML or JSON, it might be useful to know the directory of the assembly running:
var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);
You can use assemblyDirectory as base directory to store your files.
I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.
"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.
For instance, if a configuration file is like that
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
We can retrieve values like this
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
It is compatible with .NET 2.0 and higher. We can create configuration files on the fly and we can save it later.
Source: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig
Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.
If you use .NET 4.0 dynamic, this library is really easy to use
(serialize, deserialize, nested objects support and ordering output
as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
For .NET YAML configuration library... I haven't found one that is as
easy to use as JsonConfig
You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)
Sample for getting path of special folder: C# getting the path of
%AppData%
If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.
As far as I can tell, .NET does support persisting settings using the built-in application settings facility:
The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving.
- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.
I can imagine two good options:
The strongly typed version and
The object oriented version.
The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.
With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.
You can find the code of both fully functional implementations HERE.
public static class SettingsExtensions
{
public static bool TryGetValue<T>(this Settings settings, string key, out T value)
{
if (settings.Properties[key] != null)
{
value = (T) settings[key];
return true;
}
value = default(T);
return false;
}
public static bool ContainsKey(this Settings settings, string key)
{
return settings.Properties[key] != null;
}
public static void SetValue<T>(this Settings settings, string key, T value)
{
if (settings.Properties[key] == null)
{
var p = new SettingsProperty(key)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
var v = new SettingsPropertyValue(p);
settings.Properties.Add(p);
settings.Reload();
}
settings[key] = value;
settings.Save();
}
}

What's a good way to store unchanging variables in a C# project?

I'm just learning C#, so pardon my n00bness, please.
We use Visual Studio 2012 to put together a C#/Selenium project for automated testing.
We have three credit card processors.
I want to store the login credentials, test settings, and test payment items for each processor. I could do this in Python in a minute, using a dict:
processorCreds = {
'ProcOne': {
'website': '[url]',
'username': '[username]',
'password': '[password]'
},
'ProcTwo': {
'website': '[url]',
'username': '[username]',
'password': '[password]'
},
}
And then I'd just call it when I need it:
def openProcessor(procName):
urllib2.urlopen(processorCreds[procName]['website'])
openProcessor('ProcTwo')
I want this in C#, basically. I will only rarely need to change these credentials, and they'll be used in multiple test cases, so I want to be able to pull the information wherever I need it.
What would be the best way for me to put this together? Should I use an XML file, or can this be in a class, or...?
[EDIT] The alternative I see is that we set the variables each time we have a test case, which doesn't seem... object-oriented. Or, I suppose I could put the variables on the [Processor]Portal.cs pages... I was just hoping for a way to put alla this in one place with a minimum of fuss, for our occasional "this works for every processor" tests.
(Also this is totally test data, and would be accessible to the same folk who can already see it now, so I'm not worried.)
.NET offers many ways of storing constant or nearly constant data: you have a choice among multiple ways of reading XML files, configuration files, resource files with your own format, and so on. If you would like to define a structure like yours in code, you can use IDictionary:
internal static readonly IDictionary<string,dynamic> ProcessorCreds =
new Dictionary<string,dynamic> {
{"ProcOne", new {
Website = "[url]",
Username = "[username]",
Password = "[password]"
},
{"ProcTwo", new {
Website = "[url]",
Username = "[username]",
Password = "[password]"
}
};
This creates an instance of Dictionary that maps string objects to anonymous objects with three properties - Website, Username, and Password. Since objects that go in belong to an anonymous class (note the lack of class name between new and the opening curly brace) the value type of the dictionary is defined as dynamic. This would let you add more attributes in the future without changing anything else.
You can use ProcessorCreds like this:
urlopen(ProcessorCreds[procName].Website);
You can put them in App.Config( Web.Config) in the appsettings section and use the configurationmanager to get he values as shown in the example below
<appSettings>
<add key="username" value="me" />
<add key="password" value="getmein" />
</appSettings>
In the code you will have the following
string username=ConfigurationManager.AppSettings["username"];
Using C# or Python does not change the answer to this question substantially. If using a mutable in-memory data structure like a dictionary did the trick fine for you in Python, then you can just do the same in C#.
A similar answer uses dynamic, but it is more idiomatic and there are many advantages in C# to favor using static typing, like so:
public class Processor {
public Uri Website { get; private set; }
public string Username { get; private set; }
public string Password { get; private set; }
public Processor(Uri website, string username, string password) {
Website = website;
Username = username;
Password = password;
}
}
var processorCreds = new Dictionary<string, Processor> {
{ "ProcOne", new Processor(new Uri("[url]"), "[username]", "[password]") },
{ "ProcTwo", new Processor {new Uri("[url]"), "[username]", "[password]") }
};
which case be used as
processorCreds["ProcOne"].Website
There are a lot of different ways to do this. You could store the data in a static readonly dictionary.
public static readonly Dictionary<int, int> MY_DICTIONARY;
And place this inside a static class available throughout your project.
You could also store data in the Properties settings.settings file.
Generally, in my C# code I try to avoid global data and instead pass information when it is needed. This allows for code that is more easily tested.
Your question has more security and procedural implications than technical.
Since you're saving usernames and passwords for payment processing, there're all kinds of risks to storing these where they are publicly available. Do you need PCI compliance in your business? Given that this is security information, don't you want to keep them under lock-and-key to some extent? Perhaps keep them in a database, or encrypted in some way.
If there's no such issue, your appConfig file is probably the best bet: you can define them in your project, and retrieve them using the ConfigurationManager class. The will be stored in the XML file that is deployed along with your application. In plain text.
Put them in a static dynamic variable - this is the most pythonish way to do it, although it's not idiomatic c#
static dynamic processorCreds =new {
ProcOne= new {
website= "[url]",
username= "[username]",
password= "[password]"
},
ProcTwo= new {
website= "[url]",
username= "[username]",
password= "[password]"
},
}
You can then access it using var s = (string) processorCreds.ProcTwo.website;

how to specify a different location for Virtual Directories in Web Setup Projects

I want to install my virtual directory other than the default location(c:\inetpub\wwwroot).
I want that the directory will be created in the physical path enntered by the user.
Please suggest any way to do that.
not exactly what you ask but follow the steps described in the main answer here: Virtual Directory in Web Setup Project
...and instead of changing TextBoxes to not visible keep them visible so you can capture user input.
Using the System.EnterpriseServices.Internal.IISVirtualRoot you can create a Virtual direcoty through C#,
System.EnterpriseServices.Internal.IISVirtualRoot vr = new System.EnterpriseServices.Internal.IISVirtualRoot();
string sError = "";
vr.Create("IIS://localhost/W3SVC/1/Root", physicalPath, VDName, out sError);

Categories

Resources