Yahoo Fantasy Sports API - oauth-2.0

Is anyone still using the Yahoo Fantasy Sports API? I had an app that worked last year, have not changed my code at all, and now it is returning a 500 internal error when I try to run it.
I used to test things through the YQL Console, but that is no longer available.
https://developer.yahoo.com/yql/
Anyone know how to make authenticated requests on that site above?
My feeling is that Yahoo has just discontinued support for their FantasySports API, I will have to look for other solutions I think.
Wondering if anyone else out there used this API previously and is or is not still having success with it.

I figured out how to use C# core and Yahoo's API. Huge thanks to this guy
Get your api key etc from yahoo.
Make a controller action that redirects to the request URL something like this:
public IActionResult Test()
{
yo.yKey = {your Yahoo API key};
yo.ySecret = {your Yahoo API secret};
yo.returnUrl = {your return URL as set in the API setup, example "https://website.com/home/apisuccess"};
var redirectUrl = "https://api.login.yahoo.com/oauth2/request_auth?client_id=" + yo.yKey + "&redirect_uri=" + yo.returnUrl + "&response_type=code&language=en-us";
return Redirect(redirectUrl);
}
This will send you to a site that authenticates with Yahoo. Upon successful authentication it is going to send you to your redirect site with a string parameter called code, in the example it would be home/apisuccess, so that controller action should look like this:
public async Task<IActionResult> ApiSuccess(string code)
{
List<string> msgs = new List<string>(); //This list just for testing
/*Exchange authorization code for Access Token by sending Post Request*/
Uri address = new Uri("https://api.login.yahoo.com/oauth2/get_token");
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] headerByte = System.Text.Encoding.UTF8.GetBytes(_yKey + ":" + _ySecret);
string headerString = System.Convert.ToBase64String(headerByte);
request.Headers["Authorization"] = "Basic " + headerString;
/*Create the data we want to send*/
StringBuilder data = new StringBuilder();
data.Append("client_id=" + _yKey);
data.Append("&client_secret=" + _ySecret);
data.Append("&redirect_uri=" + _returnUrl);
data.Append("&code=" + code);
data.Append("&grant_type=authorization_code");
//Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
using (Stream postStream = await request.GetRequestStreamAsync())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
var vM = new yOauthResponse();
string responseFromServer = "";
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
msgs.Add("Into response");
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
responseFromServer = reader.ReadToEnd();
msgs.Add(responseFromServer.ToString());
vM = JsonConvert.DeserializeObject<yOauthResponse>(responseFromServer.ToString());
}
}
catch (Exception ex)
{
msgs.Add("Error Occured");
}
ViewData["Message"] = msgs;
return View(vM);
}
Note that I used a json deserializer of this model, but you can do whatever you want with the response to get the data you need out of it. This is my json model:
public class yOauthResponse
{
[JsonProperty(PropertyName = "access_token")]
public string accessToken { get; set; }
[JsonProperty(PropertyName = "xoauth_yahoo_guid")]
public string xoauthYahooGuid { get; set; }
[JsonProperty(PropertyName = "refresh_token")]
public string refreshToken { get; set; }
[JsonProperty(PropertyName = "token_type")]
public string tokenType { get; set; }
[JsonProperty(PropertyName = "expires_in")]
public string expiresIn { get; set; }
}
Once you have that data, the main thing you need is the access_token, and use it as follows in a controller action:
//simple code above removed
var client = new HttpClient()
{
BaseAddress = new Uri({your request string to make API calls})
};
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
//do what you will with the response....
}
//rest of simple code
Hopefully this helps someone somewhere. Happy coding!

Related

Woocommerce Create Order REST API and Xamarin Forms

I'm building a checkout page written in Xamarin Forms that creates an order in Woocommerce.
I've looked up documentation online but can't seem to find any examples or code that shows you how to do this.
My question is : is there an example code on how to create a simple order using Xamarin Forms and Woocommerce REST API?
I was able to use the REST API to pull the products from Woocommerce but can't seem to find any code examples of how to actually create an order using the REST API in Xamarin Forms.
Hope you can help.
Cheers
Here's my code woocommerceapi.cs class.
class WoocommerceAPI
{
private static string website_url = "xxxxx";
private static string consumer_key = "xxxxx";
private static string consumer_secret = "xxxxx";
private static string GetAllProductsApiUrl = string.Format("{0}/wc-api/v3/products?consumer_key={1}&consumer_secret={2}", website_url, consumer_key, consumer_secret);
private static string GetAllProductsInACategoryApiUrl = "xxxxx/wc-api/v3/products?category=379&consumer_key=xxxxx&consumer_secret=xxxxx";
public async Task<Products> GetAllProducts()
{
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(GetAllProductsApiUrl);
HttpContent content = response.Content;
var json = await content.ReadAsStringAsync();
var products = JsonConvert.DeserializeObject<Products>(json);
return products;
}
public async Task<Products> GetAllProductsInACategory()
{
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(GetAllProductsInACategoryApiUrl);
HttpContent content = response.Content;
var json = await content.ReadAsStringAsync();
var products = JsonConvert.DeserializeObject<Products>(json);
return products;
}
}
I managed to build a solution and it's now working!
Here's the code if you come across this problem and need a fix.
async void OrderBtnClicked(object sender, EventArgs e)
{
Console.WriteLine("Starting REST API");
var clientapi = new HttpClient();
clientapi = new Uri("xxxx?consumer_key=xxxx&consumer_secret=xxxx");
Console.WriteLine("Starting REST API");
var clientapi = new HttpClient();
clientapi.BaseAddress = new Uri("xxxx?consumer_key=xxxx&consumer_secret=xxxx");
// json data for adding customer
string jsonData = #"{
""first_name"" : ""John1"",
""last_name"" : ""Doe1"",
""email"" : ""john.doe1#example.com"",
""username"" : ""john.doe1"",
""password"" : ""mypassword"",
""billing"": {
""first_name"": ""John"",
""last_name"": ""Doe"",
""company"": ""john doe company"",
""address_1"": ""969 Market"",
""address_2"": """",
""city"": ""San Francisco"",
""state"": ""CA"",
""postcode"": ""94103"",
""country"": ""US"",
""email"": ""john.doe#example.com"",
""phone"": ""(555) 555-5555""
},
""shipping"": {
""first_name"": ""John"",
""last_name"": ""Doe"",
""company"": """",
""address_1"": ""969 Market"",
""address_2"": """",
""city"": ""San Francisco"",
""state"": ""CA"",
""postcode"": ""94103"",
""country"": ""US""
}
}";
Console.WriteLine("Here's the json string data");
Console.WriteLine(jsonData);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage apiresponse = await clientapi.PostAsync("xxxxx?consumer_key=xxxxx&consumer_secret=xxxx", content);
var apiresult = await apiresponse.Content.ReadAsStringAsync();
Console.WriteLine("Here's the result:");
Console.WriteLine(apiresult);
Console.WriteLine("REST API Post Completed.");
await DisplayAlert("Checkout", "Completed", "ok");
}
Obviously you can setup public variables to store the json data and you're more than welcome to do so, i'm not your dad.

Which PayPal Payment method should I use?

I have an application of my client in which he has used PaypalAdaptivePayments but the API stopped working since 2 years back, now this project is within my hands so I started investigating the API and found that PayPal has deprecated the usage of this API, actually in his application what he tends to have is this:
1- There is only 1 account of this Vendor in PayPal in which the amount debits and credits from the application.
2- Basically this application is sort of Ride booking web app, in which the customer books a ride and then deposits X amount into the wallet (remember this wallet is connected to the vendor account I have mentioned in point 1).
3- When the customer ride is completed he marks the amount as to be cleared for DEBIT, then this decision is saved into my database but till this stage the driver is not reimbursed.
4- The ADMIN logs in to this site and then he goes to the drivers list and then select an appropriate driver and then he puts in his X COMMISSION for this ride, and then clicks on PAY so with this action the driver gets paid. Note: This is a commission based procedure so for example the RIDE which an customer has booked was of USD100 so he credited this amount into the VENDORS wallet, then when the VENDOR is about to lend payment to the DRIVER he enters his own commission for e.g. 10%, so the DRIVER would be paid USD90 only. This payment is also deducted from the VENDORS wallet and then transferred to the DRIVER.
Now after painting the scenario, can you please guide me which API is best suited for this scenario? as there are LOADS of PayPal API and SDK .... I am totally lost in their world, Please keep in mind my application is build in ASP.NET MVC.
Please note:
My Client(Vendor) already owns a SANDBOX and a verified BUSINESS ACCOUNT in PayPal.
Warm Regards.
Emad.
For community ease I am sharing my code:
using Classes;
using EFare.Classes;
using PayPalMvc;
using PayPalMvc.Enums;
using SampleMVC3WebApplication.Models;
using SampleMVC3WebApplication.Services;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web;
using System.Web.Mvc;
namespace SampleMVC3WebApplication
{
public class WebUILogging
{
// Add your favourite logger here
public static void LogMessage(string message)
{
DoTrace(message);
}
public static void LogLongMessage(string message, string longMessage)
{
DoTrace(message);
DoTrace(longMessage);
}
public static void LogException(string message, Exception ex)
{
DoTrace(message);
DoTrace(ex.Message);
DoTrace(ex.StackTrace);
}
private static void DoTrace(string message)
{
Trace.WriteLine(DateTime.Now + " - " + message);
}
}
}
namespace SampleMVC3WebApplication.Services
{
public interface ITransactionService
{
SetExpressCheckoutResponse SendPayPalSetExpressCheckoutRequest(ApplicationCart cart, string serverURL,
string userEmail = null);
GetExpressCheckoutDetailsResponse SendPayPalGetExpressCheckoutDetailsRequest(string token);
DoExpressCheckoutPaymentResponse SendPayPalDoExpressCheckoutPaymentRequest(ApplicationCart cart, string token,
string payerId);
}
/// <summary>
/// The Transaction Service is used to transform a purchase object (eg cart, basket, or single item) into a sale
/// request with PayPal (in this case a cart)
/// It also allows your app to store the transactions in your database (create a table to match the PayPalTransaction
/// model)
/// You should copy this file into your project and modify it to accept your purchase object, store PayPal transaction
/// responses in your database,
/// as well as log events with your favourite logger.
/// </summary>
public class TransactionService : ITransactionService
{
private readonly ITransactionRegistrar _payPalTransactionRegistrar = new TransactionRegistrar();
public SetExpressCheckoutResponse SendPayPalSetExpressCheckoutRequest(ApplicationCart cart, string serverURL,
string userEmail = null)
{
try
{
WebUILogging.LogMessage("SendPayPalSetExpressCheckoutRequest");
// Optional handling of cart items: If there is only a single item being sold we don't need a list of expressCheckoutItems
// However if you're selling a single item as a sale consider also adding it as an ExpressCheckoutItem as it looks better once you get to PayPal's site
// Note: ExpressCheckoutItems are currently NOT stored by PayPal against the sale in the users order history so you need to keep your own records of what items were in a cart
List<ExpressCheckoutItem> expressCheckoutItems = null;
if (cart.Items != null)
{
expressCheckoutItems = new List<ExpressCheckoutItem>();
foreach (var item in cart.Items)
expressCheckoutItems.Add(new ExpressCheckoutItem(item.Quantity, item.Price, item.Name,
item.Description));
}
var response = _payPalTransactionRegistrar.SendSetExpressCheckout(cart.Currency, cart.TotalPrice,
cart.PurchaseDescription, cart.Id.ToString(), serverURL, expressCheckoutItems, userEmail);
// Add a PayPal transaction record
var transaction = new PayPalTransaction
{
RequestId = response.RequestId,
TrackingReference = cart.Id.ToString(),
RequestTime = DateTime.Now,
RequestStatus = response.ResponseStatus.ToString(),
TimeStamp = response.TIMESTAMP,
RequestError = response.ErrorToString,
Token = response.TOKEN
};
// Store this transaction in your Database
return response;
}
catch (Exception ex)
{
WebUILogging.LogException(ex.Message, ex);
}
return null;
}
public GetExpressCheckoutDetailsResponse SendPayPalGetExpressCheckoutDetailsRequest(string token)
{
try
{
WebUILogging.LogMessage("SendPayPalGetExpressCheckoutDetailsRequest");
var response = _payPalTransactionRegistrar.SendGetExpressCheckoutDetails(token);
// Add a PayPal transaction record
var transaction = new PayPalTransaction
{
RequestId = response.RequestId,
TrackingReference = response.TrackingReference,
RequestTime = DateTime.Now,
RequestStatus = response.ResponseStatus.ToString(),
TimeStamp = response.TIMESTAMP,
RequestError = response.ErrorToString,
Token = response.TOKEN,
PayerId = response.PAYERID,
RequestData = response.ToString
};
// Store this transaction in your Database
return response;
}
catch (Exception ex)
{
WebUILogging.LogException(ex.Message, ex);
}
return null;
}
public DoExpressCheckoutPaymentResponse SendPayPalDoExpressCheckoutPaymentRequest(ApplicationCart cart,
string token, string payerId)
{
try
{
WebUILogging.LogMessage("SendPayPalDoExpressCheckoutPaymentRequest");
var response =
_payPalTransactionRegistrar.SendDoExpressCheckoutPayment(token, payerId, cart.Currency,
cart.TotalPrice);
// Add a PayPal transaction record
var transaction = new PayPalTransaction
{
RequestId = response.RequestId,
TrackingReference = cart.Id.ToString(),
RequestTime = DateTime.Now,
RequestStatus = response.ResponseStatus.ToString(),
TimeStamp = response.TIMESTAMP,
RequestError = response.ErrorToString,
Token = response.TOKEN,
RequestData = response.ToString,
PaymentTransactionId = response.PaymentTransactionId,
PaymentError = response.PaymentErrorToString
};
// Store this transaction in your Database
return response;
}
catch (Exception ex)
{
WebUILogging.LogException(ex.Message, ex);
}
return null;
}
}
}
namespace SampleMVC3WebApplication.Controllers
{
public class PurchaseController : Controller
{
private readonly TransactionService transactionService = new TransactionService();
private bool checkcustomerid(string uid)
{
var dl = new AccountDataLayer();
var ds = dl.Inline_Process("select UserId from dbo.Login_Table where UserId='" + uid +
"' and UType='customer'");
return ds.Tables[0].Rows.Count > 0;
}
#region Set Express Checkout and Get Checkout Details
public ActionResult PayPalExpressCheckout()
{
WebUILogging.LogMessage("Express Checkout Initiated");
// SetExpressCheckout
var cart = (ApplicationCart)Session["Cart"];
var serverURL = HttpContext.Request.Url.GetLeftPart(UriPartial.Authority) +
VirtualPathUtility.ToAbsolute("~/");
var transactionResponse =
transactionService.SendPayPalSetExpressCheckoutRequest(cart, serverURL);
// If Success redirect to PayPal for user to make payment
if (transactionResponse == null || transactionResponse.ResponseStatus != ResponseType.Success)
{
SetUserNotification(
"Sorry there was a problem with initiating a PayPal transaction. Please try again and contact an Administrator if this still doesn't work.");
var errorMessage = transactionResponse == null
? "Null Transaction Response"
: transactionResponse.ErrorToString;
WebUILogging.LogMessage(
"Error initiating PayPal SetExpressCheckout transaction. Error: " + errorMessage);
return RedirectToAction("Error", "Purchase");
}
return Redirect(string.Format(PayPalMvc.Configuration.Current.PayPalRedirectUrl,
transactionResponse.TOKEN));
}
public ActionResult
PayPalExpressCheckoutAuthorisedSuccess(string token,
string PayerID) // Note "PayerID" is returned with capitalisation as written
{
// PayPal redirects back to here
WebUILogging.LogMessage("Express Checkout Authorised");
// GetExpressCheckoutDetails
TempData["token"] = token;
TempData["payerId"] = PayerID;
var transactionResponse =
transactionService.SendPayPalGetExpressCheckoutDetailsRequest(token);
if (transactionResponse == null || transactionResponse.ResponseStatus != ResponseType.Success)
{
SetUserNotification(
"Sorry there was a problem with initiating a PayPal transaction. Please try again and contact an Administrator if this still doesn't work.");
var errorMessage = transactionResponse == null
? "Null Transaction Response"
: transactionResponse.ErrorToString;
WebUILogging.LogMessage("Error initiating PayPal GetExpressCheckoutDetails transaction. Error: " +
errorMessage);
return RedirectToAction("Error", "Purchase");
}
return RedirectToAction("ConfirmPayPalPayment");
}
#endregion Set Express Checkout and Get Checkout Details
#region Confirm Payment
public ActionResult ConfirmPayPalPayment()
{
WebUILogging.LogMessage("Express Checkout Confirmation");
var cart = (ApplicationCart)Session["Cart"];
return View(cart);
}
[HttpPost]
public ActionResult ConfirmPayPalPayment(bool confirmed = true)
{
WebUILogging.LogMessage("Express Checkout Confirmed");
var cart = (ApplicationCart)Session["Cart"];
// DoExpressCheckoutPayment
var token = TempData["token"].ToString();
var payerId = TempData["payerId"].ToString();
var transactionResponse =
transactionService.SendPayPalDoExpressCheckoutPaymentRequest(cart, token, payerId);
if (transactionResponse == null || transactionResponse.ResponseStatus != ResponseType.Success)
{
if (transactionResponse != null && transactionResponse.L_ERRORCODE0 == "10486")
{ // Redirect user back to PayPal in case of Error 10486 (bad funding method)
// https://www.x.com/developers/paypal/documentation-tools/how-to-guides/how-to-recover-funding-failure-error-code-10486-doexpresscheckout
WebUILogging.LogMessage("Redirecting User back to PayPal due to 10486 error (bad funding method - typically an invalid or maxed out credit card)");
return Redirect(string.Format(PayPalMvc.Configuration.Current.PayPalRedirectUrl, token));
}
else
{
SetUserNotification(
"Sorry there was a problem with taking the PayPal payment, so no money has been transferred. Please try again and contact an Administrator if this still doesn't work.");
var errorMessage = transactionResponse == null
? "Null Transaction Response"
: transactionResponse.ErrorToString;
WebUILogging.LogMessage("Error initiating PayPal DoExpressCheckoutPayment transaction. Error: " +
errorMessage);
return RedirectToAction("Error", "Purchase");
}
}
if (transactionResponse.PaymentStatus == PaymentStatus.Completed)
return RedirectToAction("PostPaymentSuccess");
// Something went wrong or the payment isn't complete
WebUILogging.LogMessage("Error taking PayPal payment. Error: " + transactionResponse.ErrorToString +
" - Payment Error: " + transactionResponse.PaymentErrorToString);
TempData["TransactionResult"] = transactionResponse.PAYMENTREQUEST_0_LONGMESSAGE;
return RedirectToAction("PostPaymentFailure");
}
#endregion Confirm Payment
#region Post Payment and Cancellation
public ActionResult PostPaymentSuccess()
{
WebUILogging.LogMessage("Post Payment Result: Success");
var cart = (ApplicationCart)Session["Cart"];
ViewBag.TrackingReference = cart.Id;
ViewBag.Description = cart.PurchaseDescription;
ViewBag.TotalCost = cart.TotalPrice;
ViewBag.Currency = cart.Currency;
var dl = new Customer();
var amt = "";
var date = "";
;
var time = "";
var EFareloginCookie = Request.Cookies["Efarelogin_Cookies"];
if (EFareloginCookie != null)
if (checkcustomerid(EFareloginCookie["UserId"]))
{
amt = cart.TotalPrice.ToString();
date = DateTime.Now.ToString("yyyy-MM-dd");
time = DateTime.Now.ToString("hh:mm:ss");
var i = dl.addMoney(EFareloginCookie["UserId"], amt, date, time);
if (i > 0)
{
TempData["WalletSuccess"] = "Data saved successfully.";
//return RedirectToAction("Wallet", "Account");
ModelState.Clear();
}
else
{
TempData["Walleterror"] = "Opps something is wrong.";
}
}
return View();
}
public ActionResult PostPaymentFailure()
{
WebUILogging.LogMessage("Post Payment Result: Failure");
ViewBag.ErrorMessage = TempData["TransactionResult"];
return View();
}
public ActionResult CancelPayPalTransaction()
{
return View();
}
#endregion Post Payment and Cancellation
#region Transaction Error
private void SetUserNotification(string notification)
{
TempData["ErrorMessage"] = notification;
}
public ActionResult Error()
{
ViewBag.ErrorMessage = TempData["ErrorMessage"];
return View();
}
#endregion Transaction Error
}
}
Use PayPal Checkout for receiving money: https://developer.paypal.com/docs/checkout/ --- for a server-based API integration see the front-end UI at https://developer.paypal.com/demo/checkout/#/pattern/server
Request access to Payouts for sending money: https://developer.paypal.com/docs/payouts/integrate/prerequisites/#get-access-to-paypal-payouts

MVC app stops after SendAsync to an API - The same code runs fine in Console App though

I built a simple Console Application to test the connection to an API. Calling the connection method from Console App Main works fine. I get a response with an access-token.
I though that I just could implement the same method/code to an MVC-project and add the method within the HomeController, then call the method from any ActionResult, getting the access-token and then put it in a ViewBag to display it in a view (just for testing). But it doesn't work in the MVC-project.
If I run the debugger, it seems like the app hangs when SendAsync is executed in the method. The console gives this output:
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-04-08T09:26:32.4945663Z","tags":{"ai.internal.sdkVersion":"rddf:2.2.0-738","ai.internal.nodeName":"XXXXXX","ai.cloud.roleInstance":"XXXXXXXX"},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"/token","id":"XXXXXXXXX=","data":"https://api.vasttrafik.se/token","duration":"00:00:00.2810000","resultCode":"200","success":true,"type":"Http","target":"api.vasttrafik.se","properties":{"DeveloperMode":"true"}}}}
The thread 0x1f68 has exited with code 0 (0x0).
What can I do to make the API-call / response work in the MVC-application?
My knowledge in the area is ridiculously low. But I really want to understand whats going on here.
Thanks!
Best
J
MVC project
public class HomeController : Controller
{
public ActionResult Index()
{
string token = PostRequest().Result;
ViewBag.Token = token;
return View();
}
async static Task<string> PostRequest()
{
var client = new HttpClient();
client.BaseAddress = new Uri("https://api.vasttrafik.se");
var request = new HttpRequestMessage(HttpMethod.Post, "/token");
// Key // Secret
string credentials = "xxxxxxxxxoVS5xDrcO6qZsAp0a" + ":" + "xxxxxxxxhn0STj1w4asDwixdMa";
var plainTextBytes = Encoding.UTF8.GetBytes(credentials);
//Key and secret encoded
string encodedCrentedials = Convert.ToBase64String(plainTextBytes);
//Console.WriteLine(encodedCrentedials);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encodedCrentedials);
var formData = new List<KeyValuePair<string, string>>();
formData.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
formData.Add(new KeyValuePair<string, string>("scope", "xxxxxxxxw0oVS5xDrcO6qZsAp0a"));
request.Content = new FormUrlEncodedContent(formData);
// This is where the app hangs....
var response = await client.SendAsync(request);
var mycontentres = await response.Content.ReadAsByteArrayAsync();
var responseBody = Encoding.Default.GetString(mycontentres);
//Console.WriteLine(responseBody);
JavaScriptSerializer seri = new JavaScriptSerializer();
dynamic data = JObject.Parse(responseBody);
string tok = data.access_token;
return tok;
}
}
Don't block on async code:
public async Task<ActionResult> Index()
{
string token = await PostRequest();
ViewBag.Token = token;
return View();
}

Better way to download files directly using Amazon S3 API - SDK on ASP.MVC

Amazon provides a vast documentation, but there are so many docs that I'm lost, so here is my current service for upload/download files. Upload works as expected but on the download its where I have to download the files to a physical path and later serve the download to the user, I don't have much experience working with streams. Here is the FileManagerService class that connects to Amazon API.
using Amazon.S3;
using Amazon.S3.Model;
public class FileManagerService
{
public FileManagerService()
{
string serverPath = HttpContext.Current.Server.MapPath("~/");
string uploadPath = Path.Combine(serverPath, "FileUploads");
Directory.CreateDirectory(uploadPath);
UploadDirectory = uploadPath;
}
private string UploadDirectory { get; set; }
private docucloudEntities db = new docucloudEntities();
private IAmazonS3 S3Client = new AmazonS3Client();
private string S3Bucket = "bucketname";
public async Task<string> DownloadFile(string AmazonFileKey, string FileName)
{
var fileRequest = new GetObjectRequest
{
BucketName = S3Bucket,
Key = AmazonFileKey
};
var localRoute = Path.Combine(UploadDirectory, FileName);
using (var fileObject = await S3Client.GetObjectAsync(fileRequest))
{
if (fileObject.HttpStatusCode == HttpStatusCode.OK)
{
fileObject.WriteResponseStreamToFile(localRoute);
}
}
return localRoute;
}
}
This method returns the string, it's not complete yet with try catch blocks, but it currently works. Here is my controller method that download the file to the client:
public class FileManagerController : Controller
{
private FileManagerService FileService = new FileManagerService();
public async Task<ActionResult> DownloadFileAmazon(long FileId)
{
if (db.Archivos.Any(i => i.ArchivoID == FileId))
{
var archivo = db.Archivos.Single(i => i.ArchivoID == FileId);
var rutaarchivo = await FileService.DownloadFile(archivo.Ruta, archivo.Nombre);
if (System.IO.File.Exists(rutaarchivo))
{
var fileBytes = System.IO.File.ReadAllBytes(rutaarchivo);
var response = new FileContentResult(fileBytes, "application/octet-stream");
response.FileDownloadName = archivo.Nombre;
System.IO.File.Delete(rutaarchivo);
return response;
}else
{
return HttpNotFound();
}
}else
{
return HttpNotFound();
}
}
}
So here on the controller I read the file bytes and serve the download, after deleting the file, but this could lead to a slower perfomance, its there a way of achieving direct download.
As far as I can tell there is no reason to dispose GetObjectResponse (return type of GetObjectAsync) even if the docs says so. GetObjectResponse is not implementing IDisposable but is inheriting StreamResponse that is. However, as far as I can tell it's only disposing the ResponseStream. So you could return the stream from GetObjectResponse (fileObject.ResponseStream) together with the ContentTypefrom the headers (fileObject.Headers.ContentType) that you then can return as a file in your controller:
[HttpGet]
[Route("blob/{filename}")]
public async Task<IActionResult> GetFile(string filename)
{
try
{
var file = await _fileStorageService.GetBlobAsync(filename);
return File(file.Stream, file.ContentType);
}
catch (Exception ex)
{
// Handle exceptions
}
}
FileResult will dispose the stream after it has written the file so there the stream will finally get disposed.

consuming REST service, method returning multiple types .. what to do

I am consuming someone elses REST service for my app. the problem is that each request can return 1 of 3 different types when responding
either:
the expected successfull response type
an error response which wraps the 500 (Error)
a validation error response (ValidationErrors)
I am currently calling the service wrapping each request with a class like this:
public class ApiResponse<T>
{
public T ResponseObject { get; set; }
public ValidationErrors<ValidationError> Errors { get; set; }
public Error Error { get; set; }
}
public async Task<ApiResponse<AMethodResponse>> AMethod(AMethodRequest req)
{
ApiResponse<AMethodResponse> resp = new ApiResponse<AMethodResponse> { Errors = new ValidationErrors<ValidationError>() };
using (HttpClient client = HttpClientFactory.Create(new AuthorisationHandler(), new ContentTypeHandler()))
{
client.BaseAddress = new Uri(BaseURI);
var httpResponseMessage = await client.PostAsXmlAsync<AMethodRequest>("AMethod/", req);
if (!httpResponseMessage.IsSuccessStatusCode)
{
//its at this point that I need to work out if i am getting Validation Errors or.. a plain Error
//I can do this, but of course if its a plain error it will fall over
resp.Errors = await httpResponseMessage.Content.ReadAsAsync<ValidationErrors<ValidationError>>();
}
else
{
resp.ResponseObject = await httpResponseMessage.Content.ReadAsAsync<AMethodResponse>();
}
}
return resp;
}
I wonder if there is a more reliable pattern to writing consuming methods.
thanks
it gives a 200 for all is well. 400 for validationerror and 500 for a real error
Check the status code directly, rather than use IsSuccessStatusCode :
var httpResponseMessage = await client.PostAsXmlAsync<AMethodRequest>("AMethod/", req);
switch (httpResponseMessage.StatusCode)
{
case HttpStatusCode.OK: //200
resp.ResponseObject = await httpResponseMessage.Content.ReadAsAsync<AMethodResponse>();
break;
case HttpStatusCode.BadRequest: //400
resp.Errors = await httpResponseMessage.Content.ReadAsAsync<ValidationErrors<ValidationError>>();
break;
case HttpStatusCode.InternalServerError: //500
throw new Exception("failed"); // use appropriate exception and/or read 500 wrapper
break;
}
return resp;

Resources