I have been writing a small application using C# to copy a document into an individuals 'My Documents' folder on our DMS server.
I've beased the code around the listing provided in the 'WorkSite SDK 8: Utilize the IMANEXT2Lib.IManRefileCmd to File New Document Folders' blog.
Using this code in a WinForm application I have no problems copying the file from the source folder into the users DMS 'My Documents' folder.
However if I use the code in a command line application/.dll or any other type of application (other than WinForm) during the copy process I receive the error messages;
1.
Error occurred when try to log the event!
IManExt: Error occurred when try to log the event!
Access is denied.
2.
The document was imported to the database, but could not be added to
the folder.
IManExt: The document was imported to the database, but could not be
added to the folder.
IManExt.LogRuleEventsCmd.1: Error occurred when try to log the event!
IManExt.LogRuleEventsCmd.1: Access is denied.
Error occurred when try to log the event!
-%-
Does anyone know why I'd receiving the 'Access Denied' error messages when using a non-WinForms application to copy documents?
What would I need to do to get around this issue?
Any help would be amazing!
Code in place:
public void moveToDMS(String servName, String dBName, String foldName)
{
const string SERVERNAME = servName; //Server name
const string DATABASENAME = dBName; //Database name
const string FOLDERNAME = foldName; //Matter alias of workspace
IManDMS dms = new ManDMSClass();
IManSession sess = dms.Sessions.Add(SERVERNAME);
sess.TrustedLogin();
//Get destination database.
IManDatabase db = sess.Databases.ItemByName(DATABASENAME);
//Get destination folder by folder and owner name.
IManFolderSearchParameters fparms = dms.CreateFolderSearchParameters();
fparms.Add(imFolderAttributeID.imFolderOwner, sess.UserID);
fparms.Add(imFolderAttributeID.imFolderName, FOLDERNAME);
//Build a database list in which to search.
ManStrings dblist = new ManStringsClass();
dblist.Add(db.Name);
IManFolders results = sess.WorkArea.SearchFolders(dblist, fparms);
if (results.Empty == true)
{
//No results returned based on the search criteria.
Console.WriteLine("NO RESULTS FOUND!");
}
IManDocumentFolder fldr = null;
if (results.Empty == false)
{
//Assuming there is only one workspace returned from the results.
fldr = (IManDocumentFolder)results.ItemByIndex(1);
}
if (fldr != null)
{
// Import file path
string docPath = #"C:\Temp\";
string docName = "MyWord.doc";
// Create an instance of the ContextItems Collection Object.
ContextItems context = new ContextItemsClass();
// Invoke ImportCmd to import a new document to WorkSite database.
ImportCmd impCmd = new ImportCmdClass();
// The WorkSite object you pass in can be a database, session, or folder.
// Depends on in where you want the imported doc to be stored.
context.Add("IManDestinationObject", fldr); //The destination folder.
// Filename set here is used for easy example, a string variable is normally used here
context.Add("IManExt.Import.FileName", docPath + docName);
// Document Author
context.Add("IManExt.Import.DocAuthor", sess.UserID); //Example of a application type.
// Document Class
context.Add("IManExt.Import.DocClass", "BLANK"); //Example of a document class.
//context.Add("IManExt.Import.DocClass", "DOC"); //Example of a document class.
// Document Description (optional)
context.Add("IManExt.Import.DocDescription", docName); //Using file path as example of a description.
// Skip UI
context.Add("IManExt.NewProfile.ProfileNoUI", true);
impCmd.Initialize(context);
impCmd.Update();
if (impCmd.Status == (int)CommandStatus.nrActiveCommand)
{
impCmd.Execute();
bool brefresh = (bool)context.Item("IManExt.Refresh");
if (brefresh == true)
{
//Succeeded in importing a document to WorkSite
IManDocument doc = (IManDocument)context.Item("ImportedDocument");
//Succeeded in filing the new folder under the folder.
Console.WriteLine("New document number, " + doc.Number + ", is successfully filed to " + fldr.Name + " folder.");
}
}
}
}
Just in case this helps someone else.
It seems my issue was the result of a threading issue.
I noticed the C# winform apps I had created were automatically set to run on a single 'ApartmentState' thread ([STAThread]).
Whereas the console applications & class library thread state and management hadn't been defined within the project and was being handled with the default .NET config.
To get this to work: In the console application, I just added the [STAThread] tag on the line above my Main method call.
In the class library, I defined a thread for the function referencing the IMANxxx.dll and set ApartmentState e.g.
Thread t = new Thread(new ThreadStart(PerformSearchAndMove));
t.SetApartmentState(ApartmentState.STA);
t.Start();
In both cases ensuring single 'ApartmentState' thread was implemented set would resolve the issue.
Related
i need to create a (.txt) file on my application root on Xamarin.ios, so a need to store in memory a String, contain a UserName, after the user logged in, I can use each String to run a "httprequest" to my mySql database online. Similar procedure to the sessions in PHP, but client side and in C#.. Thanks you. I just try, with cookie, but I need to access at the UserName in every class and in every storyBoard.
I just try to write a JSON file serializable:
String NU = "NomeUtente=" + NomeUtente.Text;
string json = JsonConvert.SerializeObject(NU, Formatting.Indented);
System.IO.File.WriteAllText(#"/558gt.txt", json);
but Xamarin.ios throw a exception:
SystemUnauthorizedAccessexception -->
access to the path /558gt.txt denied.
If you need store data, use Xamarin.Essentials.SecureStorage
Check documentation
Thanks you. I read the documents on the ios file system and managed to write the portion of code necessary for reading and writing the Session file containing the username.
try {
//creo il file nella sandbox maledetta di iOS
//create file Session
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine(documents, "Session.txt");
//filename contiene la path completa di dove sta il file
File.WriteAllText(filename, NomeUtente.Text);
}
catch (Exception) {
label1.Text = "Errore generico.";
}
and now I read the file, in a separated class and storyboard:
//Recupero il nomeutente
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine(documents, "Session.txt");
var NomeUtente = File.ReadAllText(filename); //contiene il NomeUtente
I have a Windows Forms application, .Net Framework 4.6.1, and I want to store some DB connection data in an Ini file.
I then wanted to store it in the Resources file of the project (so I don't have to copy/paste the file in the Debug and Release folder manually, etc.) as a normal file, but when I tried to compile the program and read the Ini data with ini-parser, the following exception showed up: System.ArgumentException: 'Invalid characters in path access'.
I'm using Properties.Resources where I read the Ini file, so I guessed there would be no problem with the path. Could it be a problem with the Ini file itself?
The content of the Ini file is the following:
[Db]
host = (anIP)
port = (aPort)
db = (aDbName)
user = (aDbUser)
password = (aDbUserPwd)
And my method for reading the data:
public static void ParseIniData()
{
var parser = new FileIniDataParser();
IniData data = parser.ReadFile(Properties.Resources.dbc);
mysqlHost = data["Db"]["host"];
mysqlPort = data["Db"]["port"];
mysqlDb = data["Db"]["db"];
mysqlUser = data["Db"]["user"];
mysqlPwd = data["Db"]["password"];
}
I finally could do it using what #KlausGütter told me in the comments (thanks!).
Instead of using the FileIniDataParser you have to use the StreamIniDataParser, and get the Stream with Assembly.GetManifestResourceStream.
I found this a bit tricky, because using this method you need to set the Build Action in the file you want to read to Embedded Resource.
This file is then added as an embedded resource in compile time and you can retrieve its stream.
So my method ended up the following way:
public static void ParseIniData()
{
var parser = new StreamIniDataParser();
dbcReader = new StreamReader(_Assembly.GetManifestResourceStream("NewsEditor.Resources.dbc.ini"));
IniData data = parser.ReadData(dbcReader);
mysqlHost = data["Db"]["host"];
mysqlPort = data["Db"]["port"];
mysqlDb = data["Db"]["db"];
mysqlUser = data["Db"]["user"];
mysqlPwd = data["Db"]["password"];
}
where _Assembly is a private static attribute: private static Assembly _Assembly = Assembly.GetExecutingAssembly();. This gets you the assembly that's being executed when running the code (you could also use this code directly in the method, but I used the Assembly on another method in my class, so I decided to set an attribute... DRY I guess).
I've created a backup and restore procedure for my application. When the backup is run, it will create a .zip file of the SQLite database in the same directory as the database.
When restoring the database, it will rename the database, changing it from EPOSDatabase.db3 to tempEPOS.db3
Then, it takes the selected file and extracts it to the same location, under the name EPOSDatabase.db3, before deleting the renamed temporary database.
string dbPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
if (File.Exists(dbPath + "/tempEPOS.db3"))
{
File.Delete(dbPath + "/tempEPOS.db3");
};
File.Move(dbPath + "/EPOSDatabase.db3", dbPath + "/tempEPOS.db3");
ZipFile.ExtractToDirectory(dbPath + "/" + fileToRestore, dbPath + "/EPOSDatabase.db3");
File.Delete(dbPath + "/tempEPOS.db3");
My issue is that when I then have code that opens the connection, for example when I open the system settings page after the restore has been carried out, I get an error:
"Could not open database file: /data/user/0/com.companyname.ACPlus_MobileEPOS/files/EPOSDatabase.db3 (CannotOpen)"
As a further debug test, I added this code to the startup of the application:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
foreach (var file in Directory.GetFiles(path))
{
string strFile = Convert.ToString(file);
}
public readonly string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "EPOSDatabase.db3");
var db = new SQLiteConnection(dbPath);
db.CreateTable<Category>();
db.CreateTable<SystemSettings>();
db.Close();
In the foreach loop, it only found the original .zip file that I was trying to restore from.
Then when it reaches the line
var db = new SQLiteConnection(dbPath);
it fails to create the database with the message
"Could not open database file: /data/user/0/com.companyname.ACPlus_MobileEPOS/files/EPOSDatabase.db3"
It seems like the file doesn't exist, so hasn't extracted properly, but if that was the case then why does it not just create a new database, rather than try to open it?
The extraction logic needs to be rechecked.
Specifically ExtractToDirectory.
Extracts all the files in the specified zip archive to a directory on the file system.
public static void ExtractToDirectory (string sourceArchiveFileName, string destinationDirectoryName);
In the original code
ZipFile.ExtractToDirectory(dbPath + "/" + fileToRestore, dbPath + "/EPOSDatabase.db3");
The contents of the zip file are extracting to a directory called {path}/EPOSDatabase.db3/.
If the goal was just to extract from the archive to the directory then only the directory location is required.
ZipFile.ExtractToDirectory(dbPath + "/" + fileToRestore, dbPath);
Additionally, a check should be done to make sure the desired file actually exists after the restore before deleting the old file.
//... extraction code omitted for brevity
if (!File.Exists(dbPath + "/EPOSDatabase.db3")) {
//...either throw error or alert that database is not present
//...could consider return old file back to original sate (optional)
} else {
File.Delete(dbPath + "/tempEPOS.db3");
}
So I'm having a problem with automating my code to check-in files to TFS, and it's been driving me up the wall! Here is my code:
string location = AppDomain.CurrentDomain.BaseDirectory;
TfsTeamProjectCollection baseUserTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection);
IIdentityManagementService ims = baseUserTpcConnection.GetService<IIdentityManagementService>();
TeamFoundationIdentity identity = ims.ReadIdentity(IdentitySearchFactor.AccountName, #"PROD1\JR", MembershipQuery.None, ReadIdentityOptions.None);
TfsTeamProjectCollection impersonatedTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection, identity.Descriptor);
VersionControlServer sourceControl = impersonatedTpcConnection.GetService<VersionControlServer>();
Workspace workspace = sourceControl.CreateWorkspace("MyTempWorkspace", sourceControl.AuthorizedUser);
String topDir = null;
try
{
Directory.CreateDirectory(location + "TFS");
String localDir = location + "TFS";
workspace.Map("$/Automation/", localDir);
workspace.Get();
destinationFile = Path.Combine(localDir, Name + ".xml");
string SeconddestinationFile = Path.Combine(localDir, Name + ".ial");
bool check = sourceControl.ServerItemExists(destinationFile, ItemType.Any);
PendingChange[] pendingChanges;
File.Move(sourceFile, destinationFile);
File.Copy(destinationFile, sourceFile, true);
File.Move(SecondsourceFile, SeconddestinationFile);
File.Copy(SeconddestinationFile, SecondsourceFile, true);
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
else
{
workspace.PendEdit(destinationFile);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
and the problem is that whenever it's NEW files (PendEdit works correctly when the files already exist in TFS) that my code is attempting to check in, and it runs through this code:
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
The files, instead of being in the included changes in pending changes, are instead in the excluded changes like so:
and when the line that actually does the check-in runs, I'll get a "The array must contain at least one element" error, and the only way to fix it is to manually add those detected changes, and promote them to included changes, and I simply can't for the life of me figure out how to do that programatically though C#. If anyone has any guidance on what direction I should take for this, I would really appreciate it! Thank you!
Edit: I've also discovered another way to solve this by reconciling the folder, which also promotes the detected changes, but again the problem is I can't seem to figure out how to program that to do it automatically.
I know that running the visual studio developer command prompt, redirecting to the folder that this mapping is in, and the running "tf reconcile /promote" is one way, but I can only automate that as far as the /promote part, because that brings up a toolbox that a user would have to input into, which defeats the purpose of the automation. I'm at a loss.
Next Edit in response to TToni:
Next Edit in response to TToni:
I'm not entirely sure if I did this CreateWorkspaceParameters correctly (see picture 1), but this time it gave the same error, but the files were not even in the excluded portions. They just didn't show up anywhere in the pending changes (see picture 2).
Check this blog:
The workspace has a method GetPendingChangesWithCandidates, which actually gets all the “Excluded” changes. Code snippet is as below:
private void PendChangesAndCheckIn(string pathToWorkspace)
{
//Get Version Control Server object
VersionControlServer vs = collection.GetService(typeof
(VersionControlServer)) as VersionControlServer;
Workspace ws = vs.TryGetWorkspace(pathToWorkspace);
//Do Delete and Copy Actions to local path
//Create a item spec from the server Path
PendingChange[] candidateChanges = null;
string serverPath = ws.GetServerItemForLocalItem(pathToWorkspace);
List<ItemSpec> its = new List<ItemSpec>();
its.Add(new ItemSpec(serverPath, RecursionType.Full));
//get all candidate changes and promote them to included changes
ws.GetPendingChangesWithCandidates(its.ToArray(), true,
out candidateChanges);
foreach (var change in candidateChanges)
{
if (change.IsAdd)
{
ws.PendAdd(change.LocalItem);
}
else if (change.IsDelete)
{
ws.PendDelete(change.LocalItem);
}
}
//Check In all pending changes
ws.CheckIn(ws.GetPendingChanges(), "This is a comment");
}
So I have the following code, which extracts all attachments from a Contact item (residing in a shared folder):
Outlook._Application objOutlook; //declare Outlook application
objOutlook = new Outlook.Application(); //create it
Outlook._NameSpace objNS = objOutlook.Session; //create new session
Outlook.MAPIFolder oAllPublicFolders; //what it says on the tin
Outlook.MAPIFolder oPublicFolders; // as above
Outlook.MAPIFolder objContacts; //as above
Outlook.Items itmsFiltered; //the filtered items list
oPublicFolders = objNS.Folders["Public Folders"];
oAllPublicFolders = oPublicFolders.Folders["All Public Folders"];
objContacts = oAllPublicFolders.Folders["Global Contacts"];
itmsFiltered = objContacts.Items.Restrict(strFilter);//restrict the search to our filter terms
for (int i = 1; i <= itmsFiltered.Count; i++) //loop through filtered items
{
var item = itmsFiltered[i];
Contact ctctNew = new Contact(); //create new contact
foreach (Outlook.Attachment oa in item.Attachments)
{ ctctNew.ImportedAttachments.Add(oa); }
lstContacts.Add(ctctNew); // add to the list that will be displayed in the OLV
}
return lstContacts;
This seems to work fine.
I then try and save these to a file thus:
if (!System.IO.Directory.Exists(strPath))
{ System.IO.Directory.CreateDirectory(strPath); }
foreach (Outlook.Attachment o in ctLoaded.ImportedAttachments)
{
string strFilePath = strPath + #"\" + o.FileName;
if (!File.Exists(strFilePath))
{
o.SaveAsFile(strPath + #"\" + o.FileName); //exception here
}
}
This last bit works fine for filetypes that are NOT .msg - i.e. it works fine for .pdf files etc; if it's an .msg file then I get the following exception:
An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in Event Management System.exe
Additional information: Cannot save the attachment. Could not complete the operation. One or more parameter values are not valid.
Can anyone shed any light?
Thanks
UPDATE: I've discovered that it's only some of the .msg files that fail to save; some of them work fine. It seems that files attached by certain users seem to work, and files by other users don't; I'm guessing it might be to do with how they attach them?
Also it appears that the code DOES save the file (despite throwing the exception), but it appears to be corrupted - a 3Kb .msg file appears in the relevant folder. Outlook won't open it, I just get a "Unable to read the item." messagebox from Outlook if I try to open the file.
Just as a guess, what is the value of o.FileName for a msg attachment? It is possibly not a valid file name.