Add column values while uploading a file to Sharepoint with C# - c#

Currently I'm working on a project that requires the upload of files to Sharepoint. So far i can upload files programmatically without problems:
class SPAPI
{
internal void SPUploader(Stream fs, string filename)
{
ClientContext context = new ClientContext("https://....de");
System.Net.ICredentials creds = System.Net.CredentialCache.DefaultCredentials;
context.Credentials = creds;
context.RequestTimeout = 60000000; // Time in milliseconds
string fnUrl = "/software/ap_ck/Dokumenten Management System/" + filename;
Microsoft.SharePoint.Client.File.SaveBinaryDirect(context, fnUrl, fs, true);
}
}
Additionally i also have to add specific values (together with the file) to the columns in the Sharepoint document list. As this is the first time for me working with Sharepoint some of the solutions found online are a bit confusing.
One solution contains the following line:
List docList = site.Lists.GetByTitle("members");
I can only guess that the "Lists" are the storages for the files? How do i get the title of my list where i upload each files to? Sry for that stupid question, but i have never worked with Sharepoint before.

We can use Event receiver to achieve this.
First create a event receiver as below.
We can add column values after the item added(document uploaded) as below.
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using System.Web;
using System.Text;
using System.Data.SqlClient;
namespace SharePointFarmSolutionDev.DocumentEventReceiver
{
/// <summary>
/// List Item Events
/// </summary>
public class DocumentEventReceiver : SPItemEventReceiver
{
private readonly HttpContext _currentContext;
public DocumentEventReceiver()
{
if (_currentContext == null)
{
_currentContext = HttpContext.Current;
}
}
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
//init
Guid listId = properties.ListId;
int itemId = properties.ListItemId;
SPSite site = properties.Site;
SPWeb web = properties.Web;
SPList list = web.Lists[listId];
SPListItem item = list.GetItemById(itemId);
item["title"] = "hello";
item.Update();
}
}
}
More information about Event Receiver, we can refer to: Introduction To SharePoint Event Receivers

I would suggest you highlight which version of SP you are working with to get a better answer. Once you have performed the above code you would need to get a handle of the object you have just uploaded.
Uri filename = new Uri("Your file Url");
string server = filename.AbsoluteUri.Replace(filename.AbsolutePath, "");
string serverrelative = filename.AbsolutePath;
Microsoft.SharePoint.Client.File file= web.GetFileByServerRelativeUrl(serverrelative);
ListItem lstItem = file.ListItemAllFields;
clientContext.Load(lstItem);
clientContext.ExecuteQuery();
Once you have got the list handle, you can update the editor field as below
lstItem[<Field Name Here>] = <value here>
lstItem.Update();
clientContext.ExecuteQuery();
I have stolen the answer from a blog here but this should be a good starting point.
It worth remembering when you are working with doc libs you have the file you upload and an associated ListItem, Your code deals with the upload and the piece of code I have copied deals with the list item.
I've not tested this but I'm pretty sure this is how you would have to do it.
Cheers
Truez

Related

In C#, how can I create a folder if it does not exist on a SharePoint site

I am trying to create a microservice in C# which will accept a csv file containing order numbers, digest the csv, connect to sharepoint, create a new folder on sharepoint, and then copy contracts with names corresponding to the order number from whereever they may be (and they probably won't all be in the smae place) to the new folder.
At this point, with help from Stackoverflow, I can successfully get an authentication token from our Sharepoint using a CSOM Authentication Manager. And now I am trying to figure out how to create a the folder. Googling for information on creating Sharepoint folders keeps bringing up the topic of lists, which I don't know anything about and don't even know if I really want or need to know anything about, or whether there might be a different way which works with the site as that's what I'm actually interested in.
So, let's say I have a sharepoint site at https://example.sharepoint.com/sites/MySite.
How can I simply create a folder called "Foo" within a folder called "Bar" which exists in "Shared Documents"?
If I need to know something about lists in order to do this, can I use C# to find the correct list? Or do I need to chase my adminstrator for additional information?
Assuming the AuthenticationManager returns a valid context and the root folder already exists, the following works:
using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using AuthenticationManager = SharepointOrderContractExtractor.Clients.AuthenticationManager;
namespace SharePointOrderContractExtractor.Clients
{
public class FolderManager
{
private readonly AuthenticationManager _authenticationManager;
public FolderManager(
AuthenticationManager sharepointAuthenticationManager
)
{
_authenticationManager = sharepointAuthenticationManager;
}
internal Folder EnsureAndGetTargetFolder(string folderPath)
{
using ClientContext context = _authenticationManager.GetContext();
List<string> folderNames = folderPath.Split("/").ToList();
List documents = context.Web.Lists.GetByTitle(folderNames[0]);
folderNames.RemoveAt(0);
return EnsureAndGetTargetFolder(context, documents, folderNames);
}
private Folder EnsureAndGetTargetFolder(ClientContext context, List list, List<string> folderPath)
{
Folder returnFolder = list.RootFolder;
return (folderPath != null && folderPath.Count > 0)
? EnsureAndGetTargetSubfolder(context, list, folderPath)
: returnFolder;
}
private Folder EnsureAndGetTargetSubfolder(ClientContext context, List list, List<string> folderPath)
{
Web web = context.Web;
Folder currentFolder = list.RootFolder;
context.Load(web, t => t.Url);
context.Load(currentFolder);
context.ExecuteQuery();
foreach (string folderPointer in folderPath)
{
currentFolder = FindOrCreateFolder(context, list, currentFolder, folderPointer);
}
return currentFolder;
}
private Folder FindOrCreateFolder(ClientContext context, List list, Folder currentFolder, string folderPointer)
{
FolderCollection folders = currentFolder.Folders;
context.Load(folders);
context.ExecuteQuery();
foreach (Folder existingFolder in folders)
{
if (existingFolder.Name.Equals(folderPointer, StringComparison.InvariantCultureIgnoreCase))
{
return existingFolder;
}
}
return CreateFolder(context, list, currentFolder, folderPointer);
}
private Folder CreateFolder(ClientContext context, List list, Folder currentFolder, string folderPointer)
{
ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation
{
UnderlyingObjectType = FileSystemObjectType.Folder,
LeafName = folderPointer,
FolderUrl = currentFolder.ServerRelativeUrl
};
ListItem folderItemCreated = list.AddItem(itemCreationInfo);
folderItemCreated.Update();
context.Load(folderItemCreated, f => f.Folder);
context.ExecuteQuery();
return folderItemCreated.Folder;
}
}
}

Programmatically script SSIS package - Dynamic XML to OLE DB

I've been trying to piece together how other users have finished their projects, but my understanding is still limited.
I want to take any given XML source, make a Data Flow Task, and pass its data to an OLE DB destination matching the table name of the XML file. Running it with the visual tool means I cannot do dynamic data flow tasks because the Metadata does not refresh.
I have created a script that creates a package, but when I open the package in Visual Studio, it has a red-x saying that there cannot be zero Input Columns. When I drill down and look at the mappings of the OLE DB Destination, then click OK - it corrects it for me. I cannot figure out how to do that programmatically.
I've seen others solve it by using foreach loops and going through the Input columns, but I cannot seem to figure it out.
I also have a separate script that I tried to mimic several people's scripts with, and it has different issues. Not sure how to post it as an attachment
Thank you in advance for the help :)
EDIT
I've been getting positive feedback for trying out BIML, and I will...but I want to know if in the short term anyone can help me figure out why this doesn't fill in ExternalMetaDataColumnId for my input. I've posted my updated code below with foreach loops that aren't doing what I expect them to.
Thank you
#region
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using System.Xml;
#endregion
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
#region Initial Setup
Application a = new Application();
Package p = new Package();
TaskHost t = p.Executables.Add("DTS.Pipeline") as TaskHost;
t.Name = "DataFlow Task";
t.Description = "Flat File to Database";
MainPipe mp = t.InnerObject as MainPipe;
#endregion
#region Flat File Source in Dataflow Task
IDTSComponentMetaData100 md = mp.ComponentMetaDataCollection.New();
md.ComponentClassID = "Microsoft.XmlSourceAdapter";
md.Name = "XML Source";
CManagedComponentWrapper wrp = md.Instantiate();
wrp.ProvideComponentProperties();
#endregion
#region Add connection manager to OLE DB
ConnectionManager conn = p.Connections.Add("OLEDB");
conn.Name = "westcoastuserDBO";
conn.ConnectionString = "Data Source=SERVER;Initial Catalog=DBO;Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;";
#endregion
#region XML Source Properties
wrp.SetComponentProperty("XMLData", #"C:\Users\file.xml");
wrp.SetComponentProperty("XMLSchemaDefinition", #"C:\Users\file.xsd");
wrp.SetComponentProperty("AccessMode", 0);
wrp.SetComponentProperty("UseInlineSchema", false);
//below does not work
//wrp.SetComponentProperty("XMLIntegerMapping", 0).TypeConverter = "Microsoft.SqlServer.Dts.Pipeline.XmlSourceAdapter + XMLIntegerMappingConverter";
wrp.ReinitializeMetaData();
wrp.ReleaseConnections();
IDTSComponentMetaData100 md2 = mp.ComponentMetaDataCollection.New();
md2.ComponentClassID = "Microsoft.OLEDBDestination";
CManagedComponentWrapper wrp2 = md2.Instantiate();
wrp2.ProvideComponentProperties();
md2.Name = "OLE DB Connection";
md2.UsesDispositions = true;
md2.Version = 4;
wrp2.SetComponentProperty("OpenRowset", "dbo.authorizations");
#endregion
IDTSPath100 path = mp.PathCollection.New();
path.AttachPathAndPropagateNotifications(md.OutputCollection[0], md2.InputCollection[0]);
IDTSInput100 input = md2.InputCollection[0];
IDTSVirtualInput100 vInput = input.GetVirtualInput();
//below taken from https://stackoverflow.com/questions/12587709/c-sharp-ssis-data-flow-component-creating-custom-input-columns
IDTSExternalMetadataColumnCollection100 externalColumnCollection = input.ExternalMetadataColumnCollection;
// Iterate through the virtual input column collection.
foreach (IDTSVirtualInputColumn100 vColumn in vInput.VirtualInputColumnCollection)
{
// Call the SetUsageType method of the destination
// to add each available virtual input column as an input column.
wrp2.SetUsageType(
input.ID, vInput, vColumn.LineageID, DTSUsageType.UT_READONLY);
}
// Get the destination's default output collection
IDTSOutputCollection100 outColl = md2.OutputCollection;
// Iterate through the outputs in default output collection
foreach (IDTSOutput100 output in outColl)
{
// Iterate through the default output columns in the output
int count = output.OutputColumnCollection.Count;
foreach (IDTSOutputColumn100 outputColumn in output.OutputColumnCollection)
{
// Get the output's external metadata column collection
IDTSExternalMetadataColumnCollection100 extMetadataColumnColl = output.ExternalMetadataColumnCollection;
// Iterate through the external metadata column collection's external metadata columns
foreach (IDTSExternalMetadataColumn100 extMetadataColumn in extMetadataColumnColl)
{
// Call the MapOutPutColumn method of the destination to map
// each available output column to an external metadata column
wrp2.MapOutputColumn(
output.ID, outputColumn.ID, extMetadataColumn.ID, true);
}
}
}
md2.RuntimeConnectionCollection[0].ConnectionManager = DtsConvert.GetExtendedInterface(conn);
md2.RuntimeConnectionCollection[0].ConnectionManagerID = conn.ID;
conn.AcquireConnection(null);
#region Save Package to FileSystem
string packageXml = #"C:\Users\test.dtsx";
XmlDocument myPkgDocument = new XmlDocument();
p.SaveToXML(ref myPkgDocument, null, null);
a.SaveToXml(packageXml, p, null);
#endregion
}
}
}
I think the problem that you are not mapping the input columns to the OLEDB Destination, and after opening the package, if you click on the OLEDB Destination and go to the Mapping section, it will automatically map the columns based on their names. The Foreach loop that is used by others are to loop over columns and map them to the related Destination columns.
There are many articles talking about creating SSIS package dynamically, you can refer to them for more information:
Dynamic Data Flow in SSIS using .NET/C#
Programmatically map the columns of a flat file destination?
Building Packages Programmatically
Samples for creating SSIS packages programmatically
Generating SSIS Packages Programmatically (Part I)

SharePoint 2010: How to extract personalized web part property for all users

Background:
I have a built-in-house custom SharePoint 2010 web part, inheriting from System.Web.UI.WebControls.WebParts.WebPart, which has a property defined like so:
[Personalizable(PersonalizationScope.User)]
[WebBrowsable(true)]
[WebDisplayName("...")]
[WebDescription("...")]
[Category("...")]
public string CustomProp { get; set; }
The Powers-That-Be would like to know the value of the property for each of its 3,000 users. I'm already familiar with how to use the SPLimitedWebPartManager to extract the property in either shared view or my own personal view, using code similar to:
var pageUrl = "/Pages/SomePage.aspx";
var limitedManager = SPContext.Current.Web.GetLimitedWebPartManager(
pageUrl,
PersonalizationScope.User); // or .Shared, if loading the shared value
var webPart = limitedManager.WebParts.OfType<MyWebPart>().FirstOrDefault();
var prop = webPart.CustomProp;
So, the question:
I'm stuck on collecting this information for all users. Assuming I already have, or know how to retrieve, a list of login names or SPUser objects, how do I go about retrieving the web part property for all users? I can use suggestions in C#, VB.NET, or PowerShell.
Try this code - I haven't tested it but I think it should work.
const string absolutePageUrl = "http://spsite:5000/Pages/SomePage.aspx";
foreach (SPUser user in SPContext.Current.Site.RootWeb.AllUsers.Cast<SPUser>())
{
if (!user.LoginName.StartsWith("DOMAIN NAME"))
continue;
using (SPSite site = new SPSite(absolutePageUrl, user.UserToken))
using (SPWeb web = site.OpenWeb())
{
var mgr = web.GetLimitedWebPartManager(absolutePageUrl, PersonalizationScope.User);
var webPart = mgr.WebParts.OfType<MyWebPart>().FirstOrDefault();
var prop = webPart.CustomProp;
}
}

Use OpenOffice Uno CLI with C# to create a spreadsheet

I have so far found a couple of sources that discuss creation of ODS files: How to create ODS documents in .Net and
How to create .odt files with C#.NET?
And most interestingly an explanation for opening calc files. However this opens OpenOffice in fullscreen, what im looking for is some way to write to a Calc file (.ods) without actually opening Openoffice. So that I can write a function that just opens a savefiledialog, gets the filename and then creates and saves the .ods file.
Are there is any C# code examples available to do such a thing?
So I have finally resolved this issue and want to save others the hazel of going through this again. Basic points of HEADACE for me were:
Use forward slashes instead of backward slashes (e.g. its C:/ not C:\ )
The Filtername used should be set to the engine used to save the document. Possible values include writer8, calc8, MS Excel 97, so for spreadsheets you obviously need to use calc8
If you dont want that OpenOffice pops up in the forground and wait for it to get filled with your data, then use the PropertyValue and set Hidden to true.
Happy coding and dont forget to install the OpenOffice SDK to be able to add the unoidl references:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using unoidl.com.sun.star.uno;
using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.frame;
using unoidl.com.sun.star.beans;
using unoidl.com.sun.star.sheet;
using unoidl.com.sun.star.container;
using unoidl.com.sun.star.table;
using unoidl.com.sun.star.text;
namespace TimeScanner {
class ReportGenerator {
private const string fileName =
#"file:///C:/Documents and Settings/My Documents/Hours Report.ods";
//Concrete Methods
internal XComponent openCalcSheet() {
XComponentContext oStrap = uno.util.Bootstrap.bootstrap();
XMultiServiceFactory oServMan = (XMultiServiceFactory)oStrap.getServiceManager();
XComponentLoader desktop = (XComponentLoader)oServMan.createInstance("com.sun.star.frame.Desktop");
string url = #"private:factory/scalc";
PropertyValue[] loadProps = new PropertyValue[1];
loadProps[0] = new PropertyValue();
loadProps[0].Name = "Hidden";
loadProps[0].Value = new uno.Any(true);
//PropertyValue[] loadProps = new PropertyValue[0];
XComponent document = desktop.loadComponentFromURL(url, "_blank", 0, loadProps);
return document;
}
public void writeToSheet(XComponent document) {
XSpreadsheets oSheets = ((XSpreadsheetDocument)document).getSheets();
XIndexAccess oSheetsIA = (XIndexAccess) oSheets;
XSpreadsheet sheet = (XSpreadsheet) oSheetsIA.getByIndex(0).Value;
XCell cell = sheet.getCellByPosition( 0, 0 ); //A1
((XText)cell).setString("Cost");
cell = sheet.getCellByPosition( 1, 0 ); //B1
cell.setValue(200);
cell = sheet.getCellByPosition( 1, 2 ); //B3
cell.setFormula("=B1 * 1.175");
}
public void saveCalcSheet(XComponent oDoc) {
PropertyValue[] propVals = new PropertyValue[1];
propVals[0] = new PropertyValue();
propVals[0].Name = "FilterName";
propVals[0].Value = new uno.Any("calc8");
((XStorable)oDoc).storeToURL(fileName, propVals);
}
}
}

How to get SharePoint file creator name using AllDocs table?

How can I get following information about a SharePoint document.
Created By
Last modified by
I am using alldocs table of sharepoint content database but can't find it very helpful.
If you are touching the alldocs table, you aren't using the object model. Further it isn't supported and is generally a bad idea. Here is some sample code to get that same information using the object model:
using (SPSite site = new SPSite("http://your.sharepoint.server/"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Documents"];
SPListItem item = list.Items[0];
string author = (string)item["Author"];
DateTime modified = (DateTime)item["Modified"];
}
}

Categories

Resources