I'm trying to download a file from Sharepoint using a REST API. Because my app is written in .Net Core, and the CSOM library doesn't support it, I've made a "sharepoint proxy" in .Net Framework, which is a single app hosted on Azure.
Now I have a problem, while trying to download a file. I send a request from Postman to my app in .Net Core, which send another request to the sharepoint proxy, which (at last) send a GET request to Sharepoint REST API. In result, I become in Sharepoint proxy a Stream from sharepoint REST API, which I try to forward back to my app. I have no idea, which format should I use to send the file. I tried WebStream, FileStream and byte[], but in each case I got an unreadable file.
Download method in .Net Core App
public async Task<Stream> DownloadFile(SharePointFileUrl spInfo)
{
var restUrl = $"{siteUrl}/downloadFile";
using (var httpClient = new HttpClient())
{
var content = new StringContent(JsonConvert.SerializeObject(spInfo), Encoding.UTF8, "application/json");
var webResponse = await httpClient.PostAsync(restUrl, content);
return await webResponse.Content.ReadAsStreamAsync();
}
}
Endpoint in Sharepoint proxy
public byte[] DownloadFile([FromBody] SharePointFileUrl fileInfo)
{
return _spService.DownloadFile(fileInfo.FileUrl);
}
Download method in Sharepoint proxy
public byte[] DownloadFile(string url)
{
var restUrl = $"{_siteUrl}/_api/web/GetFileByServerRelativeUrl('/{url}')/$value";
var request = CreateBaseRequest("GET", restUrl);
request.Headers.Add("X-RequestDigest", _formDigest);
WebResponse fileResponse = request.GetResponse();
var input = fileResponse.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
Thank you in advance for any help. Of course, I've googled my problem, but without result.
In your Core app try this.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(new Uri("<file url string>"));
return File(req.GetResponse().GetResponseStream(), "<Content type>", "<download file name>");
Related
I have a task to call the external REST API to get data from third party application.
In that, i have created a C# Console application for tried this and it is working fine and i can get the data from thirty party application via REST API.
The same code used to tried in Dynamics Custom workflow\Plugin, i have got a error below. Please give your valuable suggestion on this.
"System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel."
Note: The below options are tried but no luck.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AlwaysGoodCertificate);
ServicePointManager.Expect100Continue = true;
Thanks,
Vasanth
It is not clear how you are calling external API from D365 Plugin.
// Call external API
static async Task<bool> CallExternalAPI(Guid beziehungId)
{
bool status = false;
HttpClient apiClient = new HttpClient();
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string url = #"https://reqres.in/api/users?page=2";
HttpResponseMessage response = await apiClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}
return status;
}
If your problem with SSL/TLS secure channel you can use WebClient.
// Could not create SSL/TLS secure channel.
// Use (SecurityProtocolType)3072
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.UserAgent, "AvoidError");
ServicePointManager.Expect100Continue = true;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
htmlCode = client.DownloadString("MY LINK");
//passing the URL again to function from which to extract the content and compare from above content.
strNewCompanyCode = client.DownloadString("MY LINK");
}
I have made a REST API and I want to use it using my Xamarin.iOS application.
Basically I want to call the API from my Xamarin application by sending some arguments to one of my API's function.
I tried the resources available at Xamarin's official website, but I a newbie so I cannot understand how it was done.
The REST API is hosted locally by the network I am using. It is not hosted at a static IP.
Kindly guide me.
You don't really need a fancy plugin if you just want to hit Web Endpoints. I simply use the basic WebRequest API.
var request = WebRequest.CreateHttp(YOUR_URL_HERE);
request.Method = "GET";
request.ContentType = "application/JSON";
request.BeginGetResponse(ResponseComplete, request);
... and then your response method can be something along the lines of...
protected void ResponseComplete(IAsyncResult result)
{
try
{
var request = result.AsyncState as HttpWebRequest;
if (request != null)
{
Debug.WriteLine("Completed query: " + request.RequestUri);
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Debug.WriteLine("Query Result: " + result);
}
}
}
}
... and if you need to post data you can add request.BeginGetRequestStream(PostData, request); before request.BeginGetResponse(ResponseComplete, request); and make your GetRequestStream handling method something along the lines of...
protected void PostData(IAsyncResult result)
{
var request = result.AsyncState as HttpWebRequest;
if (request != null)
{
using (var postStream = request.EndGetRequestStream(result))
{
var json = JsonConvert.SerializeObject(DATA_TO_POST);
Debug.WriteLine("Posting data: " + json);
var byteArray = Encoding.UTF8.GetBytes(json);
postStream.Write(byteArray, 0, byteArray.Length);
}
}
}
I would recommend Refit, you can install it as a NuGet package. Its pritty simple to use.
Refit allows us to define an interface that describes the API that we're calling, and the Refit framework handles making the call to the service and deserializing the return.
Have a look at this great blog post on how to set it up and other packages that might help you out. http://arteksoftware.com/resilient-network-services-with-xamarin/
I have used RestSharp before but Refit is alot easier to get running.
Do I need to install ASP.NET Web API Client Libraries (as this article indicates) in order to post data to a Web API server? If so, can I do so in Visual Studio 2008 from a Windows CE project?
The reasons I wonder are:
0) The client is a Windows CE project, for which I'm using Visual Studio 2008, and I don't know if ASP.NET Web API Client Libraries are available for that version; I know I don't have the NuGet Package Manager in that environment.
1) I am successfully querying data from my RESTful Web API methods without installing ASP.NET Web API Client Libraries, using code like this:
while (true)
{
deptList.departments.Clear();
string uri = String.Format("http://platypi:28642/api/Duckbills/{0}/{1}", lastIdFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest) WebRequest.Create(uri);
webRequest.Method = "GET";
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var reader = new StreamReader(webResponse.GetResponseStream());
string jsonizedDuckbills = reader.ReadToEnd();
List<Duckbill> duckbills = JsonConvert.DeserializeObject<List<Duckbill>>(jsonizedDuckbills);
if (duckbills.Count <= 0) break;
foreach (Duckbill duckbill in duckbills)
{
duckbillList.duckbills.Add(duckbill);
lastIdFetched = duckbill.Id;
}
} // if ((webResponse.StatusCode == HttpStatusCode.OK)
} // using HttpWebResponse
int recordsAdded = LocalDBUtils.BulkInsertDuckbills(duckbillList.duckbills);
totalRecordsAdded += recordsAdded;
} // while (true);
I'm stuck on posting, though, and the cleanest example I've seen so far for doing so is at that link already shown above.
I got an answer to my question on how to post here, but that hasn't made me smart enough yet to actually accomplish it. It's a step in the right direction, perhaps, although I reckon, based on how my client query code looks, that the client posting code would be of similar "style" (like the previously referenced article here, and unlike the likewise previously referenced answer here).
UPDATE
If I'm already providing the data in the uri string itself, as I am, like this:
string uri = String.Format("http://shannon2:28642/api/Departments/{0}/{1}", onAccountOfWally, moniker);
...why would I need to also specify it in postData? Or could I set postData (if that's just a necessary step to get the length) to those values...something like:
postData = String.Format("{0}, {1}", onAccountOfWally, moniker);
?
To talk to ASP.NET Web API, you do not necessarily need the client library, although it makes the life easier. After all, one of the benefits of HTTP services is the platform reach. Literally you can use any library that gives you HTTP capabilities. So, using WebRequest, you can do something like this. I'm using JSON in the payload. You can use XML and application/www-form-urlencoded as well. Just that you need to format the request body accordingly. Also, for complex objects, you will be better off using JSON.NET unlike formatting the JSON manually.
var request = System.Net.WebRequest.Create("http://localhost:12345/api/values");
request.Method = "POST";
string postData = "{\"firstName\":\"Steven\"," + "\"lastName\":\"Waugh\"}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/json";
request.ContentLength = byteArray.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(byteArray, 0, byteArray.Length);
}
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var reader = new System.IO.StreamReader(responseStream))
{
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
}
}
}
EDIT
If you are specifying data in URI, you do not need to specify the same in the request body. To let web API bind the parameters for you from URI, you will need to specify the route accordingly so that the placeholders are set for onAccountOfWally and moniker. Then you will need to use a simple type like string as action method parameters for web API to bind. By default, simple types are bound from URI path and query string and complex types from request body.
I am building a Windows Store App where I have to upload and download images from a SharePoint 2013 site. I tried the REST API but all I am getting is XML data containing the properties of the file but I am not able to get the actual file. Can someone please help me with this?
Following is the code that I am trying with:
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = false;
handler.Credentials = new NetworkCredential(userName, password, domain);
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("Accept", "application/atom+xml");
client.DefaultRequestHeaders.Add("ContentType", "application/atom+xml;type=entry");
var response = await client.GetAsync("server/site/_api/web/ListName/Items(1)/File");
Byte[] bArray = await response.Content.ReadAsByteArrayAsync();
The following example demonstrates how to retrieve a specific file content from library:
url: http://site url/_api/web/lists/getbytitle('<list title>')/items(<item id>)/File/$value
method: GET
headers:
Authorization: "Bearer " + accessToken
Example
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = client.GetAsync("https://tenant.sharepoint.com/_api/web/lists/getbytitle('Documents')/items(1)/File/$value", HttpCompletionOption.ResponseHeadersRead).Result;
var fileContent = response.Content.ReadAsByteArrayAsync().Result;
References
Working with folders and files with REST
I created my server and clients (MonoDroid and Windows) with ServiceStack, everything works very well, but now I need to consume the data from the server with a mobile client with Compact Framework F3.5.
I can access it as SOAP webservice, but I would prefer to go through REST, and use a framework to simplify things, just like the ServiceStack client (that as RestSharp is not compatible with the Compact Framework).
Do you know of something compatible with CF3.5 that lets me connect with a ServiceStack server in an easy way as
var client = new JsonServiceClient("http://192.168.0.87:82");
HelloResponse response = client.Get(new Hello { Name = "World!" });
UPDATE:
I managed to get the response with HTTPWebRequest and deserialize my HelloResponse object with an old JSON.Net version that supports the .NET Compact Framework.
The only thing that I'm missing is how to serialize my hypothetical HelloReq object and pass it to the HttpWebRequest, any hint? (without having to manually create the route as below)
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.0.87:82/Hello/test?format=json");
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream respStream = resp.GetResponseStream();
string resps;
using (var reader = new StreamReader(respStream, Encoding.UTF8))
{
resps = reader.ReadToEnd();
}
respStream.Close();
JsonTextReader jreader = new JsonTextReader(new StringReader(resps));
JsonSerializer serializer = new JsonSerializer();
HelloResponse p = serializer.Deserialize<HelloResponse>(jreader);
Thanks!
Request created:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.0.87:82/json/syncreply/Hello");
req.ContentType = "text/json";
req.Method = "POST";
req.ContentLength = json.Length;
using (var streamWriter = new StreamWriter(req.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}