Path to XML dosent work - c#

Everytime i try to save something to my created XML document the path i use keeps being wrong.
Here is the code:
public string ToXml<T>(T obj, string path)
{
var saveToXmlPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), path);
using (var stringWriter = new StreamWriter((saveToXmlPath)))
{
var xmlSerializer = new XmlSerializer(typeof(ObservableCollection<object>));
xmlSerializer.Serialize(stringWriter, obj);
return stringWriter.ToString();
}
}
public Constructor()
{
var temp = new ObservableCollection<Model> {
new Model { ID = 1, Name = "Name1" },
new Model { ID = 2, Name = "Name2" },
new Model { ID = 3, Name = "Name3" } };
ToXml(temp, #"Common\Assets\XML\XmlFile.xml");
}
It keep saying that the path is wrong, keeps adding /debug/big to the path.

Set a breakpoint on this line:
var saveToXmlPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), path);
What does it say?
Assembly.GetEntryAssembly().Location is adding /debug to your path.

Firstly, your "problem" has nothing to do with XML. You're wanting to know why Assembly.GetEntryAssembly().Location is giving you ".../bin/Debug".
Secondly... from what little information you have actually provided, there is in fact no problem at all; just your misunderstanding. Assembly.GetEntryAssembly().Location will give you the location of the executing ".exe" file (your app). In this case, that would indeed be inside the "bin/Debug" folder by default. If you want the XML file written somewhere else, then it would be helpful if you would specify where you think that somewhere else should be.

Related

JsonSerializer.Serialize throws exception

I have a list and I want to write it to a file but JsonSerializer.Serialize(mylist)throws an error
here is the code:
private void CheckIfFileExistsOrCreateOne()
{
if (!File.Exists(filePath))
{
LoginInfo secretary = new LoginInfo("secretary", "secretary", new Secretary_Form());
LoginInfo admin = new LoginInfo("admin", "admin", new Administrator_Form());
mylist.Add(secretary);
mylist.Add(admin);
File.WriteAllText(filePath, JsonSerializer.Serialize(mylist));
}
}
and the error:
It seems like you can't pass a form to a list and write it to a file because it's too large
so I changed my strategy and I used string to variable name to approach what I wanted.

C# Reading through CSV file to rename multiple files with new names

I would like to use a list of old and the corresponding new names in a CSV file(source of CSV is a Excel sheet), in order to rename files. Obviously replace the old name with the new name specified for each case.
For Example:
Find what Replace With
C:\Users\Documents\Pump Station.doc C:\Users\Documents\Awesome Pump Station.doc
C:\Users\Documents\Pump Selection.doc C:\Users\Documents\Great Pump Selection.doc
C:\Users\Documents\Pump Sizing Calc.xlsx C:\Users\Documents\Hectic Pump Sizing Calc.xlsx
I am very new to coding and I am having trouble finishing this off. This is what I have so far. I do not necessarily need to even put the list user interface (which it currently does). Ultimately I would like to loop through the rows in my CSV file, check if the old name specified exists and if so, rename it to the new name specified.
I really appreciate any help in advance and sorry for any rookie errors I may have made in my code below.
public class OldNew
{
public string oldFile { get; set; }
public string newFile { get; set; }
}
public static class OldNewService
{
public static new List<OldNew>ReadFile(string filepath)
{
var lines = File.ReadAllLines(filepath);
var data = from l in lines.Skip(1)
let split = l.Split(',')
select new OldNew
{
oldFile = split[0],
newFile = split[1],
};
return data.ToList();
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = OldNewService.ReadFile(#"C:\Users\cch\Documents\Batch Edit\Lookup Table.csv");
}
}
}
In my opinion, a better solution would be to use a plain old foreach and not a call to ToList().ForEach().
var lines = File.ReadAllLines(filepath);
var data = from l in lines.Skip(1)
let split = l.Split(',')
select new OldNew
{
oldFile = split[0],
newFile = split[1],
};
foreach(var f in data)
{
if (File.Exists(f.oldFile)
{
File.Move(f.oldFile, f.newFile);
}
}
See: http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx for an explanation.
From what I understand, you want to get the new value of the file if an old one exists. To get the new value of the file from your list, try something like:
data.ForEach(d =>
{
if (!string.IsNullOrEmpty(d.oldFile))
{
File.Move(d.oldFile, d.newFile);
}
});
Wouldn't it make sense to rename the old filename if a new one exists?
Hope this helps.

Is it possible to set/edit a file extended properties with Windows API Code Pack?

I'd like to know if it's possible to set/edit a file extended properties (Explorer: Right-click > Properties > Details) using the Windows API Code Pack.
var shellFile = Microsoft.WindowsAPICodePack.Shell.ShellObject.FromParsingName(filePath);
var artistName = shellFile.Properties.GetProperty(SystemProperties.System.Music.DisplayArtist).ValueAsObject.ToString();
var duration = TimeSpan.FromMilliseconds(Convert.ToDouble(shellFile.Properties.GetProperty(SystemProperties.System.Media.Duration).ValueAsObject) * 0.0001);
I use these few lines to get the properties I want, but I don't know how to edit one of them (the artist name for example).
I know I can use taglib-sharp, but I'll use it only if there is no solution without external code.
Thanks you all for taking the time to help me.
I found a way to edit some properties with ShellPropertyWriter but some properties are read-only.
var shellFile = ShellFile.FromParsingName(filePath);
ShellPropertyWriter w = shellFile.Properties.GetPropertyWriter();
try
{
w.WriteProperty(SystemProperties.System.Author, new string[] { "MyTest", "Test" });
w.WriteProperty(SystemProperties.System.Music.Artist, new string[] { "MyTest", "Test" });
w.WriteProperty(SystemProperties.System.Music.DisplayArtist, "Test");
}
catch (Exception ex)
{
}
w.Close();
In this sample, the 2 first occurences of ShellPropertyWriter.WriteProperty() will do exactly the same, edit the "Contributing artists" field of the file (Explorer: Right-click > Properties > Details). The third call will throw an "Access denied" exception.
Some are editable, others are not. Just need to try.
You can write to the ShellFile directly by setting the value of the properties without ShellPropertyWriter:
var shellFile = ShellFile.FromFilePath(filePath);
shellFile.Properties.System.Author.Value = new string[] { "MyTest", "Test" };
shellFile.Properties.System.Music.Artist.Value = new string[] { "MyTest", "Test" };
shellFile.Properties.System.Music.DisplayArtist.Value = "Test";
Just be aware, that to be able to edit codec-specific fields of a file, it's necessary to have the codec installed on the computer.

RavenDB throws a JSON deserialisation error when retrieving document

I've just completed a round of refactoring of my application, which has resulted in my removing a project that was no longer required and moving its classes into a different project. A side effect of this is that my User class, which is stored in RavenDB, has a collection property of a type moved to the new assembly. As soon as I attempt to query the session for the User class I get a Json deserialisation error. The issue is touched upon here but the answers don't address my issue. Here's the offending property:
{
"OAuthAccounts": {
"$type": "System.Collections.ObjectModel.Collection`1[
[Friendorsement.Contracts.Membership.IOAuthAccount,
Friendorsement.Contracts]], mscorlib",
"$values": []
},
}
OAuthAccounts is a collection property of User that used to map here:
System.Collections.ObjectModel.Collection`1[[Friendorsement.Contracts.Membership.IOAuthAccount, Friendorsement.Contracts]]
It now maps here:
System.Collections.ObjectModel.Collection`1[[Friendorsement.Domain.Membership.IOAuthAccount, Friendorsement.Domain]]
Friendorsement.Contracts no longer exists. All of its types are now in Friendorsement.Domain
I've tried using store.DatabaseCommands.StartsWith("User", "", 0, 128) but that didn't return anything.
I've tried looking at UpdateByIndex but not got very far with it:
store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Users"},
new[]
{
new PatchRequest { // unsure what to set here }
});
I'm using Raven 2.0
Below is a simple sample application that shows you the patching Metadata. While your example is a little different this should be a good starting point
namespace SO19941925
{
internal class Program
{
private static void Main(string[] args)
{
IDocumentStore store = new DocumentStore
{
Url = "http://localhost:8080",
DefaultDatabase = "SO19941925"
}.Initialize();
using (IDocumentSession session = store.OpenSession())
{
for (int i = 0; i < 10; i++)
{
session.Store(new User {Name = "User" + i});
}
session.SaveChanges();
}
using (IDocumentSession session = store.OpenSession())
{
List<User> users = session.Query<User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).ToList();
Console.WriteLine("{0} SO19941925.Users", users.Count);
}
Operation s = store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Users"},
new ScriptedPatchRequest
{
Script = #"this['#metadata']['Raven-Clr-Type'] = 'SO19941925.Models.User, SO19941925';"
}, true
);
s.WaitForCompletion();
using (IDocumentSession session = store.OpenSession())
{
List<Models.User> users =
session.Query<Models.User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).ToList();
Console.WriteLine("{0} SO19941925.Models.Users", users.Count);
}
Console.ReadLine();
}
}
internal class User
{
public string Name { get; set; }
}
}
namespace SO19941925.Models
{
internal class User
{
public string Name { get; set; }
}
}
UPDATE: Based on the initial answer above, here is the code that actually solves the OP question:
store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Users"},
new ScriptedPatchRequest
{
Script = #"this['OAuthAccounts']['$type'] =
'System.Collections.ObjectModel.Collection`1[
[Friendorsement.Domain.Membership.IFlexOAuthAccount,
Friendorsement.Domain]], mscorlib';",
}, true
);
Here are two possible solutions:
Option 1: Depending on what state your project is in, for example if you are still in development, you could easily just delete that collection out of RavenDB from the Raven Studio and recreate all those User documents. All the new User documents should then have the correct class name and assembly and should then deserialize correctly. Obviously, if you are already in production, this probably won't be a good option.
Option 2: Depending on how many User documents you have, you should be able to manually edit each one to specify the correct C# class name and assembly, so that they will be deserialized correctly. Again, if you have too many objects to manually modify, this may not be a good option; however, if there are just a few, it shouldn't be too bad to open each one up go to the metadata tab and paste the correct value for "Raven-Entity-Name" and "Raven-Clr-Type".
I ended up doing this:
Advanced.DatabaseCommands.UpdateByIndex(
"Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Album"},
new []{ new PatchRequest() {
Type = PatchCommandType.Modify,
Name = "#metadata",
Nested= new []{
new PatchRequest{
Name= "Raven-Clr-Type",
Type = PatchCommandType.Set,
Value = "Core.Model.Album, Core" }}}},
false);

How do I programmatically locate my Dropbox folder using C#?

How do I programmatically locate my Dropbox folder using C#?
* Registry?
* Environment Variable?
* Etc...
UPDATED SOLUTION
Dropbox now provides an info.json file as stated here: https://www.dropbox.com/en/help/4584
If you don't want to deal with parsing the JSON, you can simply use the following solution:
var infoPath = #"Dropbox\info.json";
var jsonPath = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), infoPath);
if (!File.Exists(jsonPath)) jsonPath = Path.Combine(Environment.GetEnvironmentVariable("AppData"), infoPath);
if (!File.Exists(jsonPath)) throw new Exception("Dropbox could not be found!");
var dropboxPath = File.ReadAllText(jsonPath).Split('\"')[5].Replace(#"\\", #"\");
If you'd like to parse the JSON, you can use the JavaScripSerializer as follows:
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var dictionary = (Dictionary < string, object>) serializer.DeserializeObject(File.ReadAllText(jsonPath));
var dropboxPath = (string) ((Dictionary < string, object> )dictionary["personal"])["path"];
DEPRECATED SOLUTION:
You can read the the dropbox\host.db file. It's a Base64 file located in your AppData\Roaming path. Use this:
var dbPath = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Dropbox\\host.db");
var dbBase64Text = Convert.FromBase64String(System.IO.File.ReadAllText(dbPath));
var folderPath = System.Text.ASCIIEncoding.ASCII.GetString(dbBase64Text);
Hope it helps!
UPDATE JULY 2016: THE CODE BELOW NO LONGER WORKS DUE TO CHANGES IN THE DROPBOX CLIENT, SEE ACCEPTED ANSWER ABOVE FOR UP-TO-DATE SOLUTION
Reinaldo's answer is essentially correct but it gives some junk output before the path because there seem to be two lines in the host.db file and in this case you only want to read the second one. The following will get you just the path.
string appDataPath = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
string dbPath = System.IO.Path.Combine(appDataPath, "Dropbox\\host.db");
string[] lines = System.IO.File.ReadAllLines(dbPath);
byte[] dbBase64Text = Convert.FromBase64String(lines[1]);
string folderPath = System.Text.ASCIIEncoding.ASCII.GetString(dbBase64Text);
Console.WriteLine(folderPath);
Cleaner version based on previous answers (use var, added exists check, remove warnings):
private static string GetDropBoxPath()
{
var appDataPath = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
var dbPath = Path.Combine(appDataPath, "Dropbox\\host.db");
if (!File.Exists(dbPath))
return null;
var lines = File.ReadAllLines(dbPath);
var dbBase64Text = Convert.FromBase64String(lines[1]);
var folderPath = Encoding.UTF8.GetString(dbBase64Text);
return folderPath;
}
This seems to be the suggested solution from Dropbox: https://www.dropbox.com/help/4584?path=desktop_client_and_web_app
Dropbox has added a new helper, there is a JSON file in either %APPDATA%\Dropbox\info.json or %LOCALAPPDATA%\Dropbox\info.json.
See https://www.dropbox.com/help/4584 for more information.
public static string getDropBoxPath()
{
try
{
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var dbPath = Path.Combine(appDataPath, "Dropbox\\host.db");
if (!File.Exists(dbPath))
{
return null;
}
else
{
var lines = File.ReadAllLines(dbPath);
var dbBase64Text = Convert.FromBase64String(lines[1]);
var folderPath = Encoding.UTF8.GetString(dbBase64Text);
return folderPath;
}
}
catch (Exception ex)
{
throw ex;
}
}
It's not stored in the registry (at least it isn't in plain text). I believe it's stored in the following location.
C:\Users\userprofile\AppData\Roaming\Dropbox
I would say it resides in the host.db or unlink.db file.
The config.db is a sqlite file. The other two are unknown (encrypted). The config.db contains a blob field only with the schema version.
The host.db method has stopped working in later versions of dropbox.
https://www.dropbox.com/en/help/4584 gives the recommended approach.
Here is the c# code I wrote to parse the json and get the dropbox folder.
// https://www.dropbox.com/en/help/4584 says info.json file is in one of two places
string filename = Environment.ExpandEnvironmentVariables( #"%LOCALAPPDATA%\Dropbox\info.json" );
if ( !File.Exists( filename ) ) filename = Environment.ExpandEnvironmentVariables( #"%APPDATA%\Dropbox\info.json" );
JavaScriptSerializer serializer = new JavaScriptSerializer();
// When deserializing a string without specifying a type you get a dictionary <string, object>
Dictionary<string, object> obj = serializer.DeserializeObject( File.ReadAllText( filename ) ) as Dictionary<string, object>;
obj = obj[ "personal" ] as Dictionary<string, object>;
string path = obj[ "path" ] as string;
return path;
I'm posting here a solution that does not use Dictionary; so many years after original answers, every time that I try to use answers from Reinaldo and Derek, I get a Could not load type 'System.Web.Util.Utf16StringValidator' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=... using both LinqPad 7 (.NET 6.0.9) and VS 2022 (Net Standard 2.0),
I do not know if this error is because I'm already referencing Newtonsoft.Json in Assembly as suggested in this unaccepted answer.
Anyway, here is 2022 piece of cake way to do it:
private static string GetDropBoxPath()
{
// https://www.dropbox.com/en/help/4584 says info.json file is in one of two places
string jsonPath = Environment.ExpandEnvironmentVariables(#"%LOCALAPPDATA%\Dropbox\info.json");
if (!File.Exists(jsonPath)) jsonPath = Environment.ExpandEnvironmentVariables(#"%APPDATA%\Dropbox\info.json");
var dropbox = JsonConvert.DeserializeObject<DropboxRoot>(File.ReadAllText(jsonPath));
return dropbox.personal.path;
}
And these are the auxiliary classes:
public class DropboxRoot
{
public Personal personal { get; set; }
}
public class Personal
{
public string path { get; set; }
public long host { get; set; }
public bool is_team { get; set; }
public string subscription_type { get; set; }
}

Categories