I am writting a winforms c# 2.0 application that needs to put an XML file into a document library on SharePoint.
I want to use a WebService instead of using the object model (no sharepoint.dll to reference here)
I am currently using the http://webserver/site/_vti_bin/copy.asmx webservice.
Here is some code:
byte[] xmlByteArray;
using (MemoryStream memoryStream = new MemoryStream())
{
xmlDocument.Save(memoryStream);
xmlBytes = memoryStream.ToArray();
}
string[] destinationUrlArray = new string[] {"http://webserver/site/Doclib/UploadedDocument.xml"};
FieldInformation fieldInfo = new FieldInformation();
FieldInformation[] fields = { fieldInfo };
CopyResult[] resultsArray;
using (Copy copyService = new Copy())
{
copyService.Credentials = CredentialCache.DefaultCredentials;
copyService.Url = "http://webserver/site/_vti_bin/copy.asmx";
copyService.Timeout = 600000;
uint documentId = copyService.CopyIntoItems("", destinationUrlArray, fields, xmlByteArray, out resultsArray);
}
When this code runs, I get a single result in the resultsArray out parameter:
DestinationURL: "http://webserver/site/Doclib/UploadedDocument.xml"
ErrorCode: UnKnown
ErrorMessage: "Object reference not set to an instance of an object."
From my searching, I have found a couple of possible helps.
Microsoft TechNet -- "The copy.asmx copyintoitems will only work if the source and destination urls are in the same SPWebApplication (Site Collection)."
Microsoft Social -- "Object reference not set to an instance of an object
error occurs because of SharePoint not able to identified that particular property."
This leads me to believe my source url should be set to something, but what? This is originating from a client workstation and does not have a source URL.
Any help would be appricated.
hank you,
Keith
I know this is an old thread but it kept coming up as I was searching for a solution to the same problem.
Check Steve Curran's answer on this thread http://social.msdn.microsoft.com/Forums/en-SG/sharepointdevelopment/thread/833e38a8-f13c-490d-8ba7-b889b6b25e38. Looks like Basically the request fails because the destination url can't be resolved.
(Limitations of a new stackflow user - can't post more than one link. See my comment for the rest)
pat
SharePoint responds to a plain old HTTP PUT
Here is what is currently working:
WebRequest request = WebRequest.Create(“http://webserver/site/Doclib/UploadedDocument.xml”);
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "PUT";
byte[] buffer = new byte[1024];
using (Stream stream = request.GetRequestStream())
{
using (MemoryStream memoryStream = new MemoryStream())
{
dataFile.MMRXmlData.Save(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
for (int i = memoryStream.Read(buffer, 0, buffer.Length); i > 0;
i = memoryStream.Read(buffer, 0, buffer.Length))
{
stream.Write(buffer, 0, i);
}
}
}
WebResponse response = request.GetResponse();
response.Close();
So... Does anyone have an opinion as to if this "PUT" method is better in the SharePoint environment than using a built-in webservice?
Right now I would have to say the "PUT" method is better since it works and I could not get the WebService to work.
Keith
your code is fine, just use the destination url instead of an empty string. See below:
byte[] xmlByteArray;
using (MemoryStream memoryStream = new MemoryStream())
{
xmlDocument.Save(memoryStream);
xmlBytes = memoryStream.ToArray();
}
string destinationUrl = “http://webserver/site/Doclib/UploadedDocument.xml”
string[] destinationUrlArray = new string[] { destinationUrl };
FieldInformation fieldInfo = new FieldInformation();
FieldInformation[] fields = { fieldInfo };
CopyResult[] resultsArray;
using (Copy copyService = new Copy())
{
copyService.Credentials = CredentialCache.DefaultCredentials;
copyService.Url = "http://webserver/site/_vti_bin/copy.asmx";
copyService.Timeout = 600000;
uint documentId = copyService.CopyIntoItems(destinationUrl , destinationUrlArray, fields, xmlByteArray, out resultsArray);
}
I get the same message when I use the default credentials.
Try replacing them with this:
copyWebService.Credentials
= new NetworkCredential("Administrator", "pass", "MyDomain");
Here's some code I wrote awhile (i apologize, i've had to piece meal it together, but hopefully you get the point of it)
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("http://sharepointsite/somefile.txt");
// Set the Method property of the request to POST.
request.Method = "PUT"
Stream dataStream;
// Set the ContentType property of the WebRequest.
request.ContentType = "multipart/form-data; charset=ISO-8859-1";
byte[] byteArray = File.ReadAllBytes(#"c:\somefile.txt");
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpStatusCode statCode = response.StatusCode;
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
I'm not sure if it will solve your problem but, when you reference the webservice, don't use the [site] part of the URL.
Try instead: http://[server]/_vti_bin/[webservice].
I'm not an expert in SP but I'm pretty sure the webservices belongs to the main server, not to an especific site.
Hope it helps.
I had a similiar problem, it turned out that the the client was configured to use NTLM security, but no NTLM header was attached.
I my case, becuase of the fact that I was using this code on the server-side of an ASP.NET applicaton, was to enable Windows authentication and set
identity impersonate="true"
in the server.web section.
if your sharepoint server is built on a farm,
Check your "Alternate Access Mapping" see if there is an entry:
yourwebserverurl intranet yourwebserverurl
if not, add it.
for my case, after adding this, the Copy service start working.
It probably due to farm load balance address resolve related.
I don't get it, why are you using Copy rather then UpdateListItems. Perhaps UpdateListItems will be a better match?
Related
I'm trying to download an Excel file from a Tableau view, using a snippet based on this article: Downloading Files with the WebRequest and WebResponse Classes.
WebResponse response = null;
Stream webStream = null;
Stream localStream = null;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = "GET";
request.Headers.Add("X-Tableau-Auth", token);
response = request.GetResponse();
webStream = response.GetResponseStream();
localStream = File.Create("testing.xlsx");
byte[] buffer = new Byte[1024];
int bytesRead;
int bytesProcessed = 0;
do
{
bytesRead = webStream.Read(buffer, 0, buffer.Length);
localStream.Write(buffer, 0, bytesRead);
bytesProcessed += bytesRead;
} while (bytesRead > 0);
response.Close();
webStream.Close();
localStream.Close();
But when I try to open the Excel file it says "Nope, maybe it is corrupt?". The response is a complete Excel file "ready to be saved", which means that it's encoded using UTF-8. Indeed, if I use Postman to do the call, and then save the response, it's saved and opens without any problem.
Before finding the page I said above, I thought the problem was because the response is UTF-8 and the class String is UTF-16. So, I made some testing getting the data from the file generated by Postman and then writing to a new file. The result of the testings: indeed, if the data passes through a String, it's not well saved. Then I tried with that code, and got the same result: fail. I'm pretty sure this code is not using any UTF-16 encoding variable, but maybe I'm wrong.
Anyway, do anyone knows what is my problem with that code, or point me to the right way to accomplish my task? That is, to download a Tableau report to Excel, using the Tableau API.
Thanks in advance.
Unless you're stuck on a particularly old version of .NET, that referenced link is from 2004. The following code will work in .NET 5 / C# 9, and in earlier versions with just some minor tweaking of the using statements. It's showing for Tableau Online, but should work fine for recent versions of Server, if I had to guess. This is sample-grade code, so I would recommend following best practices for the HttpClient if you intend to make this call frequently.
//using System.IO;
//using System.Net.Http;
var token = "your-session-token";
var uri = "https://your-pod.online.tableau.com/api/.../sites/.../views/.../crosstab/excel";
var yourFile = "D:/file/test.xlsx";
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("X-Tableau-Auth", token);
using var response = await client.SendAsync(request);
using FileStream outputFileStream = new FileStream(yourFile, FileMode.Create);
await response.Content.CopyToAsync(outputFileStream);
UPDATE: If you're constrained to WebRequest and non-async methods, you can try the following:
var token = "your-session-token";
var uri = "https://your-pod.online.tableau.com/api/.../sites/.../views/.../crosstab/excel";
var yourFile = "D:/file/test.xlsx";
WebRequest request = WebRequest.Create(uri);
request.Method = "GET";
request.Headers.Add("X-Tableau-Auth", token);
var response = request.GetResponse();
if(((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
{
using (Stream dataStream = response.GetResponseStream())
using (FileStream fileStream = new FileStream(yourFile, FileMode.CreateNew))
{
dataStream.CopyTo(fileStream);
}
}
response.Close();
I'm using Corona SDK to post data to my C# server:
headers["Content-Type"] = "application/x-www-form-urlencoded"
headers["Accept-Language"] = "en-US"
local body = "color=red&size=small"
local params = {}
params.headers = headers
params.body = body
network.request( host .. "/UpdateHand", "POST", nwListener, params )
I receive a message on the server:
Post["/UpdateHand"] = x =>
{
Console.WriteLine("Received ...");
return "Ok";
};
But when I check the data (when I put a breakpoint on it) I don't see where my data is locaded (i.e. the params.body or params.headers). How can I extract this information?
I should POST it correctly according to the documentation on Corona: http://docs.coronalabs.com/daily/api/library/network/request.html
The post data is in
this.Request.Body
If you have suitable type you can deserialize your data to it using model binding:
var x = this.Bind<YourType>();
There is a Nancy extension for this. You will need to include the namespace for it.
using Nancy.Extensions;
var text = Context.Request.Body.AsString();
I like how concise this is, part of Nancy's super-duper easy path.
But a word of caution! This method leaves the stream at the end, so subsequent calls will return empty string. To fix this, always reset the stream immediately afterwards, like so:
Request.Body.Seek(0, SeekOrigin.Begin);
Nancy 2.0 is supposed to correct this so that the stream position is reset by default.
https://github.com/NancyFx/Nancy/pull/2158
This actually works great:
var body = this.Request.Body;
int length = (int) body.Length; // this is a dynamic variable
byte[] data = new byte[length];
body.Read(data, 0, length);
Console.WriteLine(System.Text.Encoding.Default.GetString(data));
For Nancy 2.0.0, Request.Body is a Stream rather than a RequestStream, so doesn't have an AsString method. However, this seems to work:
using (var reqStream = RequestStream.FromStream(Request.Body))
{
var body = reqStream.AsString();
// ... do stuff with body
}
Ideally getting your post data could be accomplished with a simple Bind() call. However, I've seen inconsistent results when using a Bind in a post call such that I've resorted to using the scheme outlined above.
I've seen various discussions about Nancy Bind() working and not working... I've seen both with Post but cannot explain the inconsistency. Where I saw it function properly was where I could guarantee the body of the request was managed as follows:
var data = Encoding.ASCII.GetBytes (postData);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream ()) {
stream.Write (data, 0, data.Length);
}
However, when sending data that should have been similarly handled (though I couldn't confirm) through WSO2 infrastructure (data serialized as a JSON event dictionary sent to a service proxy), Bind failed while the method above succeeded.
I am trying to send contents of 1GB text file over the network. I modified the suggested code for basic authentication and kept it as follows :
WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
WRequest.Credentials = Credentials;
WRequest.PreAuthenticate = true;
WRequest.ContentType = "text/plain";
WRequest.Method = "POST";
WRequest.AllowWriteStreamBuffering = false;
WRequest.Timeout = 10000;
FileStream ReadIn = new FileStream(filename, FileMode.Open, FileAccess.Read);
ReadIn.Seek(0, SeekOrigin.Begin);
WRequest.ContentLength = ReadIn.Length;
Byte[] FileData = new Byte[ReadIn.Length];
int DataRead = 0;
Stream tempStream = WRequest.GetRequestStream();
do
{
DataRead = ReadIn.Read(FileData, 0, 2048);
if (DataRead > 0)
{
tempStream.Write(FileData, 0, DataRead);
Array.Clear(FileData, 0, 2048);
}
} while (DataRead > 0);
// The response
WResponse = (HttpWebResponse)WRequest.GetResponse();
However, now it gives me System.Net.ProtocolViolationException error : "You must write ContentLength bytes to the request stream before calling [Begin]GetResponse". I checked HttpWebRequest.BeginGetRequestResponse ... and found from debugging that the contentlength for WRequest is not -1. What else could be going wrong ? How should I get the response ?
Update :
The code which worked for small files is as followed :
WebRequest request = WebRequest.Create(url);
request.Method = "POST";
request.Credentials = Credentials;
using (StreamReader reader = new StreamReader(filename))
{
postData = reader.ReadToEnd();
}
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "text/plain";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
// The response
WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataStream))
{
responseFromServer = reader.ReadToEnd();
}
dataStream.Close();
response.Close();
The article you referenced says
If the Microsoft Internet Information Services (IIS) Web server is configured to use Basic authentication, and you must set the HttpWebRequest.AllowWriteStreamBuffering property to false, you must send a HEAD request to pre-authenticate the connection before you send the POST or PUT request.
EDIT - now with more clarification!
To restate the article, if you want to send a large file to a destination which requires basic authentication, you'll need to issue two separate requests. The key here is that you are setting PreAuthenticate = true. Read the statement literally -- by setting the property to true, you are saying that you will authenticate any requests that you make before you actually attempt them! The framework doesn't know how you want to accomplish this pre-authentication, so you need to perform that action yourself, by sending a HEAD request to the destination. Think of the HEAD HTTP method as being a prologue to the actual request - it describes (or requests information about) a particular resource.
So the process goes like this:
Make a HEAD request to http://someurl/aresource containing the credentials you want to use when making future requests from this client to that server for the listed resource
The server will respond (ideally) with "OK - you may proceed. You're authenticated"
The server immediately regrets its' decision to allow the operation as it finds itself saving a very large file :-)
I don't see you making that HEAD request anywhere in the code you posted - if it's not already there, add this at the beginning of your code (snipped from the sample article ref in OP):
//preAuth the request
// You can add logic so that you only pre-authenticate the very first request.
// You should not have to pre-authenticate each request.
WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
// Set the username and the password.
WRequest.Credentials = new NetworkCredential(user, password);
WRequest.PreAuthenticate = true;
WRequest.UserAgent = "Upload Test";
WRequest.Method = "HEAD";
WRequest.Timeout = 10000;
WResponse = (HttpWebResponse)WRequest.GetResponse();
WResponse.Close();
// Make the real request.
I am new to WCF and Rest services, and tried to do some implementation from posts I found on the web, but I am still getting some problems.
So let me explain my scenario.
I have a WPF application, and in it I have a feedback form, which the client can fill up, attach some screenshots, and send it. Now my idea was to gather all this info inside an XML file, which I am already doing successfully, and then uploading this XML file on my server in a particular folder.
Now as I understand it, the client app has to have a POST method to post the stream to the server, and then I should have an aspx page on the server to decode back the stream I get from the POST, and formulate my XML file, and then save it inside the folder, correct me if I'm wrong.
At the moment I have implemented the code on the client as follows :-
public static void UploadFile()
{
serverPath = "http://localhost:3402/GetResponse.aspx";
filePath = "C:\\Testing\\UploadFile\\UploadFile\\asd_asd_Feedback.xml";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serverPath);
//request.MediaType = "text/xml";
request.ContentType = "text/xml";
//request.Method = "POST";
request.Method = "POST";
//request.ContentLength = contentLength;
//request.ContentType = "application/x-www-form-urlencoded";
using (FileStream fileStream = File.OpenRead(filePath))
using (Stream requestStream = request.GetRequestStream())
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int byteCount = 0;
while ((byteCount = fileStream.Read(buffer, 0, bufferSize)) > 0)
{
requestStream.Write(buffer, 0, byteCount);
}
}
string result = String.Empty;
try
{
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
}
catch (Exception exc)
{
}
if (result == "OK")
{
}
else
{
// error...
}
}
Now how can I pass the requestStream to the GetResponse.aspx page? And is this the correct way to go?
Thanks for your help and time
I don't understand what your code is trying to do. Have you considered actually using a WCF client and a WCF service for doing the actual upload itself?
There is a sample that does this! This blog post details how to use the programming model on the service side, and this follow-up blog post details how to use it on the client side. I've seen it used quite a bit for file upload and image transfer scenarios, so it might help your situation as well! The example present in those blog posts is a file upload one.
Hope this helps!
I am having difficulty in consuming the reCaptcha Web Service using C#/.Net 3.5. Although I think the problem is with consuming web services in general.
String validate = String.Format("http://api-verify.recaptcha.net/verify?privatekey={0}&remoteip={1}&challenge={2}&response={3}", PrivateKey, UserIP, Challenge, Response);
WebClient serviceRequest = new WebClient();
serviceRequest.Headers.Add("ContentType","application/x-www-form-urlencoded")
String response = serviceRequest.DownloadString(new Uri(validate ));
It keeps telling me that the error is: nverify-params-incorrect. Which means:
The parameters to /verify were incorrect, make sure you are passing all the required parameters.
But it's correct. I am using the private key, the IP address (locally) is 127.0.0.1, and the challenge and response seem fine. However the error keeps occurring.
I am pretty sure this is a issue with how I am requesting the service as this is the first time I have actually used webservices and .Net.
I also tried this as it ensures the data is posted:
String queryString = String.Format("privatekey={0}&remoteip={1}&challenge={2}&response={3}",PrivateKey, UserIP, Challenge, Response);
String Validate = "http://api-verify.recaptcha.net/verify" + queryString;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(Validate));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = Validate.Length;
**HttpWebResponse captchaResponse = (HttpWebResponse)request.GetResponse();**
String response;
using (StreamReader reader = new StreamReader(captchaResponse.GetResponseStream()))
response = reader.ReadToEnd();
Seems to stall at the point where I get response.
Any advice?
Thanks in advance
Haven't worked with the recaptcha service previously, but I have two troubleshooting recommendations:
Use Fiddler or Firebug and watch what you're sending outbound. Verifying your parameters would help you with basic troubleshooting, i.e. invalid characters, etc.
The Recaptcha Wiki has an entry about dealing with development on Vista. It doesn't have to be limited to Vista, though; if you're system can handle IPv6, then your browser could be communicating in that format as a default. It appears as if Recaptcha deals with IPv4. Having Fiddler/Firebug working would tell you about those other parameters that could be causing you grief.
This may not help solve your problem but it might provide you with better troubleshooting info.
So got this working, for some reason I needed to write the request to a stream like so:
//Write data to request stream
using (Stream requestSteam = request.GetRequestStream())
requestSteam.Write(byteData, 0, byteData.Length);
Could anyone explain why this works. I didn't think I would need to do this, don't completely understand what's happening behind the scenes..
Damien's answer is correct of course, but just to be clear about the order of things (I was a little confused) and to have a complete code sample...
var uri = new Uri("http://api-verify.recaptcha.net/verify");
var queryString = string.Format(
"privatekey={0}&remoteip={1}&challenge={2}&response={3}",
privateKey,
userIP,
challenge,
response);
var request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = queryString.Length;
request.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(queryString);
}
string result;
using (var webResponse = (HttpWebResponse)request.GetResponse())
{
var reader = new StreamReader(webResponse.GetResponseStream());
result = reader.ReadToEnd();
}
There's a slight difference in that I'm writing the post variables to the request, but the core of it is the same.