This is my first time ever with Sharepoint. Here is the scenario
I have a stand alone web application
I also have a stand alone sharepoint server.
Both are on different servers.
I need to upload a file from web application to sharepoint
I found 2 methods online,
Using the webservice provided by Sharepoint (CopyIntoItems)
Using jQuery library of Sharepoint webservice
After searching the web, I think the jQuery part will not work (you can correct me).
I am looking for a method that takes username/password and uploads a pdf file to Sharepoint server. The following is my C# code that tries to upload but ends up in error
public bool UploadFile(string file, string destination)
{
bool success = false;
CopySoapClient client = new CopySoapClient();
if (client.ClientCredentials != null)
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
try
{
client.Open();
string filename = Path.GetFileName(file);
string destinationUrl = destination + filename;
string[] destinationUrls = { destinationUrl };
FieldInformation i1 = new FieldInformation { DisplayName = "Title", InternalName = "Title", Type = FieldType.Text, Value = filename };
FieldInformation[] info = { i1 };
CopyResult[] result;
byte[] data = File.ReadAllBytes(file);
//uint ret = client.CopyIntoItems(filename, destinationUrls, info, data, out result);
uint ret = client.CopyIntoItems(file, destinationUrls, info, data, out result);
if (result != null && result.Length > 0 && result[0].ErrorCode == 0)
success = true;
}
finally
{
if (client.State == System.ServiceModel.CommunicationState.Faulted)
client.Abort();
if (client.State != System.ServiceModel.CommunicationState.Closed)
client.Close();
}
return success;
}
I am calling the above function like this
UploadFile(#"C:\temp\uploadFile.txt", "http://spf-03:300/demo/Dokumente").ToString();
Error that i get:
Error Code: Destination Invalid
Error Message: The service method 'Copy' must be called on the same domain that contains the target URL.
There is the 3rd option with SharePoint 2010 and that is to use the Client Side object model. The client side object model a a sub set of the larger Sharepoint API, but it does cover uploading documents. Below is blog post with an example of uploading.
Upload document through client object model
As with most things in SharePoint you will need to authenticate against it the site, so find out if your site collection is forms based or claims based and then you should be able to find sample code for your situation.
Solution to the problem:
The problem was that the "security token webservice" was not working and it was giving some error when we manually ran the webservice.
The server was unable to process the request due to an internal error.
For more information about the error, either turn on
IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute
or from the configuration behavior) on the server in order to send the
exception information back to the client, or turn on tracing as per
the Microsoft .NET Framework 3.0 SDK documentation and inspect the
server trace logs.
The above exception is a generic one. To view the exact exception we enabled remote error viewing from the web.config file of the webservice(link) and saw the exact exception.
We found the solution for the exception and the service started. After that everything was working fine.
Related
I'm trying to use Microsoft.Identity.Client and Microsoft.SharePoint.Client libraries to authenticate to an On-premise SharePoint server and then query it.
I obtain the Azure AD access token from which the SharePoint server is a part of like following:
private readonly string[] m_scopes = { "user.read", "https://sql.azuresynapse-dogfood.net/user_impersonation" };
var publicAppBuilder = PublicClientApplicationBuilder.Create("MyClientId").WithAuthority("https://login.microsoftonline.com/a******com.onmicrosoft.com");
publicAppBuilder.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
var app = publicAppBuilder.Build();
AuthenticationResult result = null;
result = app.AcquireTokenInteractive(m_scopes).ExecuteAsync().GetAwaiter().GetResult();
if (result != null)
{
m_mediator.AccessToken = result.AccessToken;
}
When I get the access token I put it in the request header as follows:
args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + m_mediator.AccessToken;
Which is inside the ClientContext.ExecutingWebRequest subscribed method:
clientContext.ExecutingWebRequest += (sender, args) =>
which is triggered by
context.ExecuteQuery();
The remote server returned an error: (401) Unauthorized.
or
The remote server returned an error: (403) Forbidden.
How can I establish the connection? I want to avoid using app-only registration, I want to authenticate using Azure AD MFA (Interactive) method.Please note that I have all the permissions needed and I am an admin on both Azure AD where SharePoint is joined, as well on the SharePoint server itself. I authenticate through the browser just fine.
I've tried multiple things so far:
I tried creating a separate request where I forward the previously acquired accessToken as Authorization: Bearer token
I tried reading the FedAuth from the authentication connection window, so I can forward it in my HTTP request but with no success
I tried creating a "Web browser" using a WebBrowser C# class and reading the cookies that are on a browser level like the following: cookieContainer = webBrowser1.Document.Cookie; but I had no success.
I'm expecting to Authenticate via Azure AD and then connect to SharePoint in order to query it
To resolve the error "The remote server returned an error: (401)
Unauthorized", please try checking the following:
Check whether your URL is correct:
The SharePoint Online URL must always start with HTTPS.
$SiteURL` `=` `"https://crescent.sharepoint.com/sites/marketing"`
Check if you have the right permissions to the site:
Check whether you have sufficient permissions and you are able to open the site in the browser. Make sure to have SharePoint Online Administrator Role.
Check whether the Legacy authentication protocol is enabled:
Make sure to enable Legacy authentication protocol in your tenant, if it is not enabled.
Reference : SharePoint Online: Fix "The remote server returned an error (401) Unauthorized" Error in PowerShell - SharePoint Diary
To resolve the error "The remote server returned an error: (403)
Forbidden.", please try checking the following:
Make sure whether you have provided correct URL and credentials.
Make sure whether you have installed latest version of SharePoint Online Client Component SDK.
Try adding yourself to the site explicitly
Check the lock status of your site and unlock if it is locked.
Please check if any conditional access policies is enabled in your tenant.
If you try to connect to the Tenant Admin site, make sure the Tenant Admin URL like below:
https://YourDomain-admin.sharepoint.com
Reference : SharePoint Online: Fix "The remote server returned an error: (403) Forbidden." Error in PowerShell - SharePoint Diary.
I've found a solution.
I basically iterate through all cookies whenever a browser navigates through a new page and parse all the cookies until I get the fedAuth cookie:
I created a web browser from System.Windows.Forms.WebBrowser
In the WebBrowserNavigatedEventHandler for Navigated I do the following:
if (webBrowser1.Url.AbsoluteUri == "about:blank")
{
return;
}
var cookieData = GetWebBrowserCookie.GetCookieInternal(webBrowser1.Url, false);
if (string.IsNullOrEmpty(cookieData) == false)
{
var dict = ParseCookieData(cookieData);
if (dict.ContainsKey("FedAuth") && !string.IsNullOrEmpty(dict["FedAuth"]))
{
m_mediator.FedAuthCookie = dict["FedAuth"];
if (dict.ContainsKey("rtFa") && !string.IsNullOrEmpty(dict["rtFa"]))
{
m_mediator.RtFaCookie = dict["rtFa"];
}
m_mediator.UpdateConfiguration();
this.Close();
}
}
The ParseCookieData method looks like this:
private IDictionary<string, string> ParseCookieData(string cookieData)
{
var cookieDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrEmpty(cookieData))
{
return cookieDictionary;
}
var values = cookieData.TrimEnd(';').Split(';');
foreach (var parts in values.Select(c => c.Split(new[] { '=' }, 2)))
{
var cookieName = parts[0].Trim();
var cookieValue = parts.Length == 1 ? string.Empty : parts[1];
cookieDictionary[cookieName] = cookieValue;
}
return cookieDictionary;
}
and GetWebBrowserCookie class looks like this:
[SecurityCritical]
public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
uint pchCookieData = 0;
string url = UriToString(uri);
uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;
//Gets the size of the string builder
if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
{
pchCookieData++;
StringBuilder cookieData = new StringBuilder((int)pchCookieData);
//Read the cookie
if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
{
DemandWebPermission(uri);
return cookieData.ToString();
}
}
int lastErrorCode = Marshal.GetLastWin32Error();
if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
{
throw new Win32Exception(lastErrorCode);
}
return null;
}
private static void DemandWebPermission(Uri uri)
{
string uriString = UriToString(uri);
if (uri.IsFile)
{
string localPath = uri.LocalPath;
new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
}
else
{
new WebPermission(NetworkAccess.Connect, uriString).Demand();
}
}
private static string UriToString(Uri uri)
{
if (uri == null)
{
return string.Empty;
}
UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
}
This way we open up a pop-up C# web browser, authenticate the user through the web using MFA and then close the browser when we acquire an authentication cookie so we can continue working with HTTP requests towards the Sharepoint server.
Source: https://github.com/OceanAirdrop/SharePointOnlineGetFedAuthAndRtfaCookie
Hi i am using liferay/api/secure/jsonws services to upload documents, getting documents, from a outside application , in the same way i want to download the documents also, i checked my liferay jsonws , there is no method or service which i can use for download , or i don't know about it , please suggest me a way to download documents from outside application , by using jsonws or any other way is also fine.
Edit after i got to know how to download document.
Hi I tried to download liferay document from outside application by using getURl, but every time for all document i am getting liferay login page content
i have already tried get-file-as-stream json-rpc call but that also giving me null response
the code which i have used is:
final HttpHost targetHost = new HttpHost(hostname.trim());
System.out.println(targetHost.getHostName());
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
System.out.println(creds);
final AuthScope authscope = new AuthScope(targetHost);
httpclient.getCredentialsProvider().setCredentials(authscope, creds);
final AuthCache authCache = new BasicAuthCache();
final BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
final BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
final HttpGet httpget = new HttpGet(hostname+"/documents/" + groupId + "/" + folderId + "/" + filename);
final HttpResponse response = httpclient.execute( httpget, localContext);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
final org.apache.http.HttpEntity entity = response.getEntity();
if (entity != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
return baos.toByteArray();
}
}
return null;
} finally {
httpclient.getConnectionManager().shutdown();
}
}
i am adding basic auth header will correct username and password, don't know how this login page is coming, is there any permission which i need to change or any configurations issue, please help in this.
You could use the Liferay WebDav Services to download files from your document-library. The paths to download can be inspected inside of the control-panel when clicking on a file entry (WebDAV URL toogle link). The paths usually look like: /webdav/{site-name}/document_library/{folder-name}/{file-name}
Otherwise, you could mimic the request URLs Liferay creates inside the documents-media portlet to download the file entry.
But you should take care about authentication, when your files (and folders) are not visible to guests.
I have researched for days and not found an answer. I have used both google and Stack and MDSN so I finally thought it is time to ask the question. I am a new developer I completed my first assignment and my computer died. I got Win 8.1 pro and IIS 8.5 and now I am tasked with making that work with SQL 2012. I have it so I can load up the localhost to the first page of the app which is a login and then when I am debuging using Visual Studio after I start to log in
the first call to the db this comes up
An exception of type 'System.ServiceModel.ProtocolException' occurred in mscorlib.dll but was not handled in user code
Additional information: The remote server returned an unexpected response: (405) Method Not Allowed.
Then I get the same message again and then it sends me to the error page.
I am an IIS newbie, but I have ensured IUSER has the correct authorization and I have checked all of the web.configs, as well as the applicationHost file. This has to be a IIS problem is what I have come up but I would gladly be wrong if someone told me I was wrong and corrected. Thanks for the help.
Code Example
The first call to db where the first error pops up
MYapp.GlobalDataService.GlobalDataServiceClient gdc = new Myapp.Proxy.GlobalDataService.GlobalDataServiceClient();
ReadLogosResult result = gdc.GetLogos(_customerId, region_id, branch_id);
if (result != null)
{
logoContent = result.Logo;
}
This is after clicking login
public static int GetUserId(IIdentity contextIdentity)
{
FormsIdentity identity = contextIdentity as FormsIdentity;
if (identity == null)
{
throw new ApplicationException("cannot cast context identity to FormsIdentity type");
}
return Convert.ToInt32(identity.Ticket.UserData.Split(';')[0]);
}
Then this
for (int i = 0; i < ContextKeys.Length; i++)
{
string ContextKey = ContextKeys[i];
if (ContextKey == "appErr")
{
obj = (Exception)HttpContext.Current.Application["appErr"];
HttpContext.Current.Application.Remove("appErr");
}
if (ContextKey == "userId")
{
user = (int)HttpContext.Current.Application["userId"];
HttpContext.Current.Application.Remove("userId");
}
}
errors out Object reference not set to an instance of an object
then goes to our customer error page
I got it figured out. I needed to install HTTPActivation in WCF.
I'm trying to read a value from a list in a remote SharePoint site (different SP Web App). The web apps are set up with Claims Auth, and the client web app SP Managed account is configured with an SPN. I believe Kerberos and claims are set up correctly, but I am unable to reach the remote server, and the request causes an exception: "The remote server returned an error: (401) Unauthorized."
The exception occurs in the line ctx.ExecuteQuery(); but it does not catch the exception in the if (scope.HasException) instead, the exception is caught by the calling code (outside of the using{} block).
When I look at the traffic at the remote server using Wireshark, it doesn't look like the request is even getting to the server; it's almost as if the 401 occurs before the Kerberos ticket is exchanged for the claim.
Here's my code:
using (ClientContext ctx = new ClientContext(contextUrl))
{
CredentialCache cc = new CredentialCache();
cc.Add(new Uri(contextUrl), "Kerberos", CredentialCache.DefaultNetworkCredentials);
ctx.Credentials = cc;
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ExceptionHandlingScope scope = new ExceptionHandlingScope(ctx);
Web ctxWeb = ctx.Web;
List ctxList;
Microsoft.SharePoint.Client.ListItemCollection listItems;
using (scope.StartScope())
{
using (scope.StartTry())
{
ctxList = ctxWeb.Lists.GetByTitle("Reusable Content");
CamlQuery qry = new CamlQuery();
qry.ViewXml = string.Format(ViewQueryByField, "Title", "Text", SharedContentTitle);
listItems = ctxList.GetItems(qry);
ctx.Load(listItems, items => items.Include(
item => item["Title"],
item => item["ReusableHtml"],
item => item["ReusableText"]));
}
using (scope.StartCatch()) { }
using (scope.StartFinally()) { }
}
ctx.ExecuteQuery();
if (scope.HasException)
{
result = string.Format("Error retrieving content<!-- Error Message: {0} | {1} -->", scope.ErrorMessage, contextUrl);
}
if (listItems.Count == 1)
{
Microsoft.SharePoint.Client.ListItem contentItem = listItems[0];
if (SelectedType == SharedContentType.Html)
{
result = contentItem["ReusableHtml"].ToString();
}
else if (SelectedType == SharedContentType.Text)
{
result = contentItem["ReusableText"].ToString();
}
}
}
I realize the part with the CredentialCache shouldn't be necessary in claims, but every single example I can find is either running in a console app, or in a client side application of some kind; this code is running in the codebehind of a regular ASP.NET UserControl.
Edit: I should probably mention, the code above doesn't even work when the remote URL is the root site collection on the same web app as the calling code (which is in a site collection under /sites/)--in other words, even when the hostname is the same as the calling code.
Any suggestions of what to try next are greatly appreciated!
Mike
Is there a reason why you are not using the standard OM?
You already said this is running in a web part, which means it is in the context of application pool account. Unless you elevate permissions by switching users, it won't authenticate correctly. Maybe try that. But I would not use the client OM when you do have access to the API already.
yes, i know about File.Copy(...), but is there a web service method that can do the same thing? i am also worried about credentials needed to access the server. the inputs are to be the report filepath and the url to the server i want to move the report to WITHOUT CHANGING THE FORMAT. i have been looking at the web service ReportService2005 but not so sure it will work. other web services i have available are: ReportExecution2005, ReportingServices, ReportService, and ReportService2006. i would like to stay away from using rs.exe as well.
// Determine filename without extension (used as name in SSRS)
FileInfo fileInfo = new FileInfo(FileSystemPath);
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName);
try
{
// Determine filecontents
Byte[] fileContents = File.ReadAllBytes(fileInfo.FullName);
// Publish report
rsService.Warning[] warnings = this.rs.CreateReport(fileNameWithoutExtension, this.SSRSFolder, true, fileContents, null);
if (warnings != null)
{
foreach (rsService.Warning warning in warnings)
{
//Log warnings
}
}
}
catch
{
//handle error
}