Retrieve 'Last Saved By' file property programmatically - c#

I'm trying to access the 'Last Saved By' file property using C# as part of an MVC web app. I'm able to get pretty much every other property on the file from last modified date, to the owner and I've even used Shell32 to get really obscure properties.
However, I cannot find a way to get the 'Last Saved By' property when I am retrieving the audit properties for each file that I need to report on. The files I need to get this data from are all Excel.

The 'Last Saved By' property can be read using the WindowsAPICodePack.Shell libraries. This property is application specific, so it is not present on some files (for example it is available on .xls but not .csv). The 'Last Saved By' file property is named 'LastAuthor'.
I used nuget to get the package and the code below to access the property:
string lastSavedBy = null;
using (var so = ShellObject.FromParsingName(file))
{
var lastAuthorProperty = so.Properties.GetProperty(SystemProperties.System.Document.LastAuthor);
if (lastAuthorProperty != null)
{
var lastAuthor = lastAuthorProperty.ValueAsObject;
if (lastAuthor != null)
{
lastSavedBy = lastAuthor.ToString();
}
}
}

You can access the property in
Workbook.BuiltinDocumentProperties(7)
Maybe it will have index 6 when accessed from the C#. See MSDN documentation.
Quick verification: in Immediate Window (Ctrl+G) of Excel VBA editor (Alt+F11) you can type
? ThisWorkbook.BuiltinDocumentProperties(7) and hit Enter to display the property. This is the Excel part.
There is also part how to call Excel from the C#, but I am not going to cover this one, you can find literally hundreds of answers and examples on this topic.
Maybe even more effective can be just adding reference to Microsoft.Office.Tools.Excel Namespace and working directly, without Excel.

Related

Set a permanent value of a variable without using a database

I don't know how to describe it thoroughly in the title, but I need to set a permanent value of a variable/flag once a process has return true and maybe set some flag in the program itself the value rather than saving it to database. And once that variable/flag has already have that value then the program won't run the process again and just use the value. Is it possible? I'm using VB.Net. I can't use the database because database can be overridden and change values by using query. Thanks in advance!
You can simply use binary/XML serialization in a file to save the state of that variable through your program. Every time you restart your app you can access the value from that file to get its current state.
You can look at this example - http://www.centerspace.net/examples/nmath/csharp/core/binary-serialization-example.php
Basically, you will not save the value in the database but in a file. Anyways you need to persist the value somewhere.
Some ways below
You did not specify if you are afraid that your application or another one could change the value
How I would do it
My ideas below
1)You could use an xml file for example and zip a copy of it with a strong password. Every time you update the first xml you will update also the encrypted zipped xml.You can use a FileSystemWatcher and capture any file change, so if something/someone has changed the file you just get a new copy from the zip
2)You can store the value in the DB and add a trigger to prevent delete/update
for example
-- delete trigger
CREATE TRIGGER Function_Value_Deleted
ON [dbo].[FunctionsValueTb]
AFTER DELETE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT [Flag] FROM deleted
)
BEGIN
ROLLBACK;
RAISERROR ('Record deletion is not allowed...', 16, 1);
END
END
*You can use also use THROW rather than RAISERROR
**Do the same for the insert and update actions
***You can also store the value into a log table or send an email
I found myself in a situation quite similar to yours a couple of days ago.
In the end, I decided to use the settings functionaly provided by .NET: it is easy to use and maintain, and so far it has given me good results.
Yo can see here what I am talking about:
Best practice to save application settings in a Windows Forms Application
That thread refers to C# but is easily applicable for VB.NET: I just had to follow the same steps in order to add the Settings file:
Right click on the project in Solution Explorer, choose Properties.
Select the Settings tab, 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
And then, from my code, I use the settings like this:
Dim lastExecDate As Date = My.Settings.LastSuccessfulExecution
lastExecDate = lastExecDate.AddDays(1)
// Perform my next execution and do other stuff
My.Settings.LastSuccessfulExecution = lastExecDate
My.Settings.Save()
Next time you retrieve the parameter LastSuccessfulExecution, it will have the updated value.
One more remark, as stated in the post that I linked above:
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
Finally, I see that you are using this to store the expiration date of a product, so you don't want the user messing around with it. According to this post, the actual values of the parameters are stored in an Application Data user folder. It is somehow obfuscated since it is not that easy to find and besides it contains a hash on its name... I don't know if that is well hidden enough for you.
If you want the value only to exist in memory when the application is running then you can use the main thread of the application and use:
int slotData = randomGenerator.Next(1, 200);
//to set the data
Thread.SetData(Thread.GetNamedDataSlot("SomeDataKey"), slotData);
//to get the data
int newSlotData = (int)Thread.GetData(Thread.GetNamedDataSlot("SomeDataKey"));
Or you can use the Windows Registry if your app only runs on Windows, if not then you would have to write the value/object to a file and read it from there.

EPPlus - How to rename a named range and maintain correct formulas?

I have an Excel file with a named range (just one cell). There are other cells who's formulas use this name. I am trying to programatically rename the cell using EPPlus. My first attempt I simply removed the old name and added the new:
workbook.Names.Remove("OldName");
workbook.Names.Add("NewName", mySheet.Cells["B2"]);
This worked to rename the range, but the formulas still use "OldName" so they now come up with #NAME? instead of the corresponding cell's value.
If I get a reference to the name using LINQ like var nameReference = workbook.Names.First(x => x.Name == "OldName") I notice by trying to set the name property like nameReference.Name == "NewName" that it is a read-only property.
Is there a method I haven't seen for renaming these named ranges? If not, what alternatives are there to my situation? If I could get a reference to all cells who's formulas call this named range I could change each formula. I think I would need to simply scan every used cells' formulas for this reference, which I think would take a while, especially considering I actually may have dozens of Excel workbooks to scan through.

Saving custom settings or attributes in a Word document

I've got a MS Word project where I'm building a number of Panes for users to complete some info which automatically populates text at bookmarks throughout the document. I'm just trying to find the best way of saving these values somehow that I can retrieve them easily when re-opening the document after users have typed in their values.
I could just try to retrieve them from the bookmarks themselves but of course in many cases they contain text values when I'd ideally want to store a primary key somewhere that's not visible to the user and just in case they made changes to the text which would make reverse engineering the values impossible.
I can't seem to find any information on saving custom attributes in a Word document, so would really appreciate some general guidance of how this might be achieved.
Thanks a lot!
I would suggest the use of custom document properties. there you can strings in a key -value manner (at least if it is similar to excel).
I found a thread which explains how to do it:
Set custom document properties with Word interop
After playing around with this a fair bit this is my final code in case it helps someone else, I've found this format easier to understand and work with. It's all based on the referenced article by Christian:
using Office = Microsoft.Office.Core;
using Word = Microsoft.Office.Interop.Word;
using System.Reflection;
Office.DocumentProperties properties = (Office.DocumentProperties)Globals.ThisDocument.CustomDocumentProperties;
//Check if the property exists already
if (properties.Cast<Office.DocumentProperty>().Where(c => c.Name == "nameofproperty").Count() == 0)
{
//Then add the property and value
properties.Add("nameofproperty", false, Office.MsoDocProperties.msoPropertyTypeString, "yourvalue");
}
else
{
//else just update the value
properties["nameofproperty"].Value = "yourvalue";
}
In terms of retrieving the value it's as easy as using the same three lines at the top to get the properties object, perhaps using the code in the if statement to check if it exists, and the retrieving it using properties["nameofproperty"].Value

Loading a Null String and Silverlight 4

I maintain a Silverlight 4 application. While I was out of the office, the database structure was changed and a table was dropped and its fields combined into another existing table. Now, I’m receiving the following error after I create a new item and proceed to its "summary" screen:
“Value cannot be null. Parameter name: Text
At System.Windows.Controls.TextBox.set_Text(String value)”
This only happens with newly created entries, not older entries where the information on the next screen is complete (data was converted from an Excel spreadsheet and loaded into the database). So, I’ve narrowed it down this: the child window that is used to create a new record doesn’t have all the fields that were added to the table because some of the information isn’t available when the record is created. A Google search turned up that null strings can’t be passed in Silverlight.
The Summary screen is loaded via ddsSummaryLoadedData domain service. If I don’t include the “new” fields, then the values aren’t loaded for existing entries, but new entries don’t cause an error. If I do include them, older entries load correctly but new ones give the above error.
Is there a workaround to create the empty fields until they’re needed, but still load data if it exists (for older entries)? Or does the child window need to be redesigned? I’m new to Silverlight and still have so much to learn!
It doesn't look like you're using Bindings to render your view otherwise null values will be handled gracefully, so if you are setting the Text property manually in code, use the cascading operator to verify you are not submitting a null value.
myTextBox.Text = myModelValue.FirstName ?? string.Empty;

Unable to Update Sharepoint Document Properties: Required Fields are Empty

I am updating Documents on Sharepoint using the List.asmx web service.
But problem I am facing is:
Fields are not getting updated as some of required fields are not added.
But to fill required fields I have to Update again.
"ID" field is compulsary at the time of Update.
Which we get only after uploading Document. (We get this id by "ows_id" attribute value.)
Edit: As said by "Janis Veinbergs" We can't get this ID until document is actualy saved.
So how will I update document as ID field is must for Update?
If I don't Put ID Field:
Error : 0x8102000aInvalid URL Parameter
The URL provided contains an invalid Command or Value. Please check the URL again.
If I put Null Value to it:
Error :0x81020016Item does not exist
The page you selected contains an item that does not exist. It may have been deleted by another user.
Is there any way to set document properties at the time of uploading files on Sharepoint?
****Note: I am uploading file in Chunck.And Not using Microsoft.sharepoint.dll ****
Language: C#.
I tried this code.
But here again properties are being set after uploading file.
number 2 -> One is for sure - you can't get database row ID of document before it is actually saved into database.
The page linked to in the question actually links to a newer option using a FrontPage RPC method to post documents to SharePoint:
http://geek.hubkey.com/2007/11/upload-file-to-sharepoint-document.html
I would use that instead.
If you need to upload multiple files, you can use this method. If you need to upload one file, try this one.

Categories

Resources