Razorpay payment gateway integration asp.net core - asp.net-core-webapi

I am beginner to integrate razorpay payment gateway on our angular and asp.net core website. Getting 500 error while posting the data to gateway url. Please check my code and pour your answers. Ia m searching it for nearly 2 days.
public async Task<IActionResult> CreateOrder([FromBody] TicketSales Sales)
{
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
string razorkey = "key";
string secret = "secret";
RazorpayClient client = new RazorpayClient(razorkey, secret);
Dictionary<string, object> options = new Dictionary<string, object>();
options.Add("amount", Sales.subTotal.Replace(".", "")); // amount in the smallest currency unit
options.Add("receipt", "Receipt_567");
options.Add("currency", "INR");
options.Add("payment_capture", "0");
Order order = client.Order.Create(options);
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("https://api.razorpay.com/v1/checkout/embedded");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("key",razorkey),
new KeyValuePair<string, string>("Amount", Sales.subTotal),
new KeyValuePair<string, string>("currency", "INR"),
new KeyValuePair<string, string>("name",Sales.bName),
new KeyValuePair<string, string>("description","Test Transaction"),
new KeyValuePair<string, string>("imag", ""),
new KeyValuePair<string, string>("order_id",Convert.ToString(order["id"])),
new KeyValuePair<string, string>("callback_url","localhost:4200//signin"),
});
var result = await httpClient.PostAsync("https://api.razorpay.com/v1/checkout/embedded", content);
if (result.IsSuccessStatusCode)
{
}
}
return Json(new { orderId = order["id"].ToString(),result });
}

check razorpay .net reference here
you have to post the error then someone may give you the solution!

For JavaScript client, you should consider the following flow while using asp.net core,
I have used it with the React.js client but you can find some similarities and make it work for the Angular.
This is the official documentation link for javascript client integration with your backend server,
https://razorpay.com/docs/payment-gateway/web-integration/standard/#step-1-create-an-order-from-your-server
This is my React.js client app handler which will be called on button click,
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
const handleRazorpayPayment = () => {
const data = {}; // here anything extra can be passed while creating an order
const response = await axios.post(`api/payment/initialize`, data);
const order_id = response.data.id;
const options = {
key: `razorpay_key`,
amount: 200,
name: 'Your javascript client app',
description: 'Pro Membership',
image: '/your_logo.png',
order_id: order_id,
handler: (response) => {
axios.post(`api/payment/confirm`, response)
.then(response=>alert(response.data))
.catch((err)=>console.log(err))
},
prefill: {
name: "TESTUSER",
email: "testuser#mail.com",
},
theme: {
color: '#F37254'
}
};
const rzp1 = new window.Razorpay(options);
rzp1.open();
};
This is the PaymentController.cs which will create an Order using Razorpay client library,
[Route("api/[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private RazorpayClient _razorpayClient;
public PaymentController()
{
_razorpayClient = new RazorpayClient("key", "secret");
}
[HttpPost]
[Route("initialize")]
public async Task<IActionResult> InitializePayment()
{
var options = new Dictionary<string, object>
{
{ "amount", 200 },
{ "currency", "INR" },
{ "receipt", "recipt_1" },
// auto capture payments rather than manual capture
// razor pay recommended option
{ "payment_capture", true }
};
var order = _razorpayClient.Order.Create(options);
var orderId = order["id"].ToString();
var orderJson = order.Attributes.ToString();
return Ok(orderJson);
}
public class ConfirmPaymentPayload
{
public string razorpay_payment_id { get; }
public string razorpay_order_id { get; }
public string razorpay_signature { get; }
}
[HttpPost]
[Route("confirm")]
public async Task<IActionResult> ConfirmPayment(ConfirmPaymentPayload confirmPayment)
{
var attributes = new Dictionary<string, string>
{
{ "razorpay_payment_id", confirmPayment.razorpay_payment_id },
{ "razorpay_order_id", confirmPayment.razorpay_order_id },
{ "razorpay_signature", confirmPayment.razorpay_signature }
};
try
{
Utils.verifyPaymentSignature(attributes);
// OR
var isValid = Utils.ValidatePaymentSignature(attributes);
if (isValid)
{
var order = _razorpayClient.Order.Fetch(confirmPayment.razorpay_order_id);
var payment = _razorpayClient.Payment.Fetch(confirmPayment.razorpay_payment_id);
if (payment["status"] == "captured")
{
return Ok("Payment Successful");
}
}
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return StatusCode(StatusCodes.Status500InternalServerError);
}
}

Related

Fetching JSON data with .netcore from a web api

I made an api which have some data for example www.example.com/data/select?indent=on&q=title:asthma
gives the data in JSON format like
{
"responseHeader":{
"status":0,
"QTime":2,
"params":
{
"q":"title:asthma",
"indent":"on",
"wt":"json"
},
"response":{"numFound":1,"start":0, docs:[
{
"tstamp": "xxxx"
"id": "xxxxx"
"title": "Asthma is a medical term"
"url": "www.example.com/xxxx"
"content":"xxxxx"
}]}
}}
I want to call the same url from my .netcore application such that I can have title and url from the response and show it to my .netcore application.
As a new to .netcore it is pretty tricky to get used to MVC architecture. My model look like this
namespace searchEngineTesting.Models
{
public class SearchModel
{
public string Title {get; set;}
public string Source {get; set;}
}
}
How can I use controller that whenever triggers take a string as an input for example cancer and put it to the title of the api like www.example.com/data/select?indent=on&q=title:cancer and fetch the title and url from the response.
You could fetch json data like below:
[HttpGet]
public async Task<JsonResult> Get()
{
var model = new SearchModel();
var url = "https://localhost:5001/api/values/test";//it should be the url of your api
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync(url))
{
using (var content = response.Content)
{
//get the json result from your api
var result = await content.ReadAsStringAsync();
var root = (JObject)JsonConvert.DeserializeObject(result);
var items = root.SelectToken("responseHeader").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach(var item in items)
{
if(item.Key== "response")
{
var key = item.Value.SelectToken("").OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var k in key)
{
if(k.Key== "docs")
{
var tests = JsonConvert.DeserializeObject<JArray>(k.Value.ToString());
var data = k.Value.SelectToken("").Children().First();
var test = data.SelectToken("").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var t in test)
{
if (t.Key == "url")
{
model.Source = t.Value.ToString();
}
else if (t.Key=="title")
{
model.Title = t.Value.ToString();
}
}
}
}
}
}
return new JsonResult(model);
}
}
}
}
[HttpGet("[Action]")]
public string test()
{
//for easy testing,I just read your json file and return string
var jsonstring = System.IO.File.ReadAllText("C:\\test.json");
return jsonstring;
}

How to implement OpenID OAuth2 Server in ASP.NET Framework 4.x Web API?

I'm trying to implement OpenID OAuth 2.0 server with ASP.NET Framework 4.7.2 Web API. It will be used to protect resource APIs with JWT Access/Refresh tokens.
I'm fairly new to OpenID and OAuth so I'm looking for advice/guidelines/libray that I can use to implement this Authorization server.
The Auth server needs to be implemented by using ASP.NET Framework 4.7.2, there is no option for Core at the moment. The resource APIs will be written in ASP.NET Core 2.X.
I've followed the awesome Taiseer's tutorials (Part 1, Part 3, Part 5, and JWT Setup), and currently have OAuth server which can generate JWT Tokens, and Core API which can validate the token.
Here is the code that I currently have.
Auth Server:
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
app.CreatePerOwinContext<SecurityUserManager>(SecurityUserManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new SmAuthorizationServerProvider(),
RefreshTokenProvider = new SmRefreshTokenProvider(),
AccessTokenFormat = new SmJwtFormat("http://localhost:7814"),
ApplicationCanDisplayErrors = true,
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
SmAuthorizationServerProvider.cs
public class SmAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId = string.Empty;
string clientSecret = string.Empty;
Client client = null;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (context.ClientId == null)
{
//Remove the comments from the below line context.SetError, and invalidate context
//if you want to force sending clientId/secrects once obtain access tokens.
context.Validated();
//context.SetError("invalid_clientId", "ClientId should be sent.");
return Task.FromResult<object>(null);
}
using (AuthRepository _repo = new AuthRepository())
{
client = _repo.FindClient(context.ClientId);
}
if (client == null)
{
context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId));
return Task.FromResult<object>(null);
}
if (client.ApplicationType == Models.ApplicationTypes.NativeConfidential)
{
if (string.IsNullOrWhiteSpace(clientSecret))
{
context.SetError("invalid_clientId", "Client secret should be sent.");
return Task.FromResult<object>(null);
}
else
{
if (client.Secret != Helper.GetHash(clientSecret))
{
context.SetError("invalid_clientId", "Client secret is invalid.");
return Task.FromResult<object>(null);
}
}
}
if (!client.Active)
{
context.SetError("invalid_clientId", "Client is inactive.");
return Task.FromResult<object>(null);
}
context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);
context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
SecurityUser user = null;
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
using (AuthRepository _repo = new AuthRepository())
{
user = await _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
string scopes = null;
if (context.Scope.Count > 0)
{
scopes = string.Join(" ", context.Scope.Select(x => x.ToString()).ToArray());
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
// Add the user id as claim here
// Keep the claims number small, the token length increases with each new claim
identity.AddClaim(new Claim("sid", user.Id.ToString()));
// add the client id as claim
if (!string.IsNullOrEmpty(context.ClientId))
{
identity.AddClaim(new Claim("client_id", context.ClientId));
}
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
},
{
"as:scope", (scopes == null) ? string.Empty : scopes
},
{
"userName", context.UserName
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
var currentClient = context.ClientId;
// check if the token is created with specified client_id
if (!string.IsNullOrEmpty(currentClient) && !string.IsNullOrEmpty(originalClient))
{
if (originalClient != currentClient)
{
context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
return Task.FromResult<object>(null);
}
}
var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
// Change auth ticket for refresh token requests if needed
// newIdentity.AddClaim(new Claim("newClaim", "newValue"));
var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
context.Validated(newTicket);
return Task.FromResult<object>(null);
}
public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
{
Client client;
using (AuthRepository _repo = new AuthRepository())
{
client = _repo.FindClient(context.ClientId);
}
var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
oAuthIdentity.AddClaim(new Claim("client_id", client.Id));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
}
});
var ticket = new AuthenticationTicket(oAuthIdentity, props);
context.Validated(ticket);
return base.GrantClientCredentials(context);
}
}
SmJwtFormat.cs
public class SmJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private const string AudiencePropertyKey = "as:scope";
private readonly string _issuer = string.Empty;
private AuthRepository authRepo;
private SecurityKey signingKey;
private string secret = "P#ssw0rd-7BBF8546-C8C1-44D9-A404-9E1CAF80EC9D-F2FEC38D-2041-499E-9FAA-218C8B1EEC7B";
public SmJwtFormat(string issuer)
{
_issuer = issuer;
authRepo = new AuthRepository();
// Generating the signingKey
string symmetricKeyAsBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(secret));
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
signingKey = new SymmetricSecurityKey(keyByteArray);
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
// The token audience from the JWT terminology is the same as the token Scope in OAuth terminology.
string scope = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;
if (string.IsNullOrWhiteSpace(scope)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience/scope");
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
if (scope != null)
{
var scopesList = scope.Split(' ').ToList();
var audClaims = scopesList.Select(s => new Claim("aud", s));
data.Identity.AddClaims(audClaims);
}
var token = new JwtSecurityToken(_issuer, null, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = _issuer,
IssuerSigningKey = signingKey,
};
var handler = new JwtSecurityTokenHandler();
SecurityToken token = null;
// Unpack token
var pt = handler.ReadJwtToken(protectedText);
string t = pt.RawData;
var principal = handler.ValidateToken(t, tokenValidationParameters, out token);
var identity = principal.Identities;
return new AuthenticationTicket(identity.First(), new AuthenticationProperties());
}
}
Here is my resource ASP.NET Core 2.2 API Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthorization();
// identity http://localhost:7814
// resource https://localhost:44337
var key = "P#ssw0rd-7BBF8546-C8C1-44D9-A404-9E1CAF80EC9D-F2FEC38D-2041-499E-9FAA-218C8B1EEC7B";
string symmetricKeyAsBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(key));
var keyByteArray = Convert.FromBase64String(symmetricKeyAsBase64);
var securityKey = new SymmetricSecurityKey(keyByteArray);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.Authority = "http://localhost:7814/";
o.RequireHttpsMetadata = false;
o.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = "http://localhost:7814",
ValidateAudience = true,
ValidAudiences = new List<string>()
{
"api1"
},
//IssuerSigningKey = securityKey
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
}
Currently I'm able to generate tokens by posting to http://localhost:7814/oauth2/token with the following parameters:
grant_type=password
username=user1
password=p#ssw0rd
client_id=smLocalhost
client_secret=secret
scope=api1 api2
After that the token can be used to access secured endpoints in the resource API.
I've researched IdentityServer4, OpenIdDict and AspNet.Security.OpenIdConnect.Server, but they seems to be working only with ASP.NET Core.
So after all this stuff, my questions are:
1. How to add OpenID on top of that?
2. Is there a library that I can use?
3. Could you please give me tutorial/advice what can I do to implement
it?
4. How to implement discovery document endpoint (.well-known/openid-configuration) and rotate the public keys for asymmetric token signing?
Thanks in advance!

xamarin forms listview auto refresh

I'm new to Xamarin.Forms and I'm making a Listview that needs to update every time I insert new information in the database, so far I can display the info of my list and add it via a PHP file but I can't make it refresh automatically.
namespace Proyect
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Alarms : ContentPage
{
public Alarms ()
{
InitializeComponent();
AlarmsList.ItemTemplate = new DataTemplate(typeof(Cells.AlarmsCell)); //Template of the Alarms
this.LoadAlarms();
}
private async void LoadAlarms()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("Http://192.168.0.13");
string url = string.Format("/Proyect/alarmscode.php?");
var response = await client.GetAsync(url);
var result = response.Content.ReadAsStringAsync().Result;
var jsonalarms = JsonConvert.DeserializeObject<ObservableCollection<GetAlarms>>(result);
AlarmsList.ItemsSource = jsonalarms;
}
catch (Exception e)
{
await DisplayAlert("ERROR", e + "", "OK");
return;
}
}
}
}
Can you try to keep the same ObservableCollection and update its content instead of setting a new ObservableCollection every time?
namespace Proyect
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Alarms : ContentPage
{
private ObservableCollection<GetAlarms> _itemsSource = null;
public Alarms()
{
InitializeComponent();
AlarmsList.ItemTemplate = new DataTemplate(typeof(Cells.AlarmsCell)); //Template of the Alarms
_itemsSource = new ObservableCollection<GetAlarms>();
AlarmsList.ItemsSource = _itemsSource;
this.LoadAlarms();
}
private async void LoadAlarms()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("Http://192.168.0.13");
string url = string.Format("/Proyect/alarmscode.php?");
var response = await client.GetAsync(url);
var result = response.Content.ReadAsStringAsync().Result;
var jsonalarms = JsonConvert.DeserializeObject<ObservableCollection<GetAlarms>>(result);
_itemsSource.Clear();
foreach (var alarm in jsonalarms)
{
_itemsSource.Add(alarm);
}
}
catch (Exception e)
{
await DisplayAlert("ERROR", e + "", "OK");
return;
}
}
}
}
Device.StartTimer (new TimeSpan (0, 0, 10), () => {
// do something every 10 seconds
return true; // runs again, or false to stop
});

Stripe.net in Xamarin.Forms PCL with ASP.NET Core MVC Web API

I am trying to implement Stripe.net into my Xamarin.Forms PCL using an ASP.NET Core MVC Web API. The goal is to process credit card payment from users. My web API runs locally on http://localhost:port for testing purposes.
In the PaymentPage, a user enters their credit card information into Entry objects and when they click the submit Button, a method in the PaymentPageViewModel is called to start the logic:
async void OnFinishBookingClicked(object sender, System.EventArgs e)
{
// TODO: Stripe integration
var viewModel = (PaymentPageViewModel)this.BindingContext;
await viewModel.ProcessPayment();
}
This is part of the PaymentPageViewModel:
private readonly IStripeRepository _repository;
private readonly IAPIRepository _api;
public PaymentPageViewModel(IStripeRepository repository, IAPIRepository api)
{
_repository = repository;
_api = api;
}
public async Task ProcessPayment()
{
try
{
if (string.IsNullOrEmpty(ExpirationDate))
ExpirationDate = "09/18";
var exp = ExpirationDate.Split('/');
var token = _repository.CreateToken(CreditCardNumber, exp[0], exp[1], SecurityCode);
await Application.Current.MainPage.DisplayAlert("Test Message", token, "OK");
await _api.ChargeCard(token, 5.00M);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
}
}
This is what the APIRepository looks like:
public class APIRepository: IAPIRepository
{
const string Url = "http://localhost:5000";
private string authorizationKey;
private async Task<HttpClient> GetClient()
{
HttpClient client = new HttpClient();
if (string.IsNullOrEmpty(authorizationKey))
{
authorizationKey = await client.GetStringAsync(Url);
authorizationKey = JsonConvert.DeserializeObject<string>(authorizationKey);
}
client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
client.DefaultRequestHeaders.Add("Accept", "application/json");
return client;
}
public async Task<string> ChargeCard(string token, decimal amount)
{
HttpClient client = await GetClient();
var json = JsonConvert.SerializeObject(new { token, amount });
var response = await client.PostAsync("/api/Stripe", new StringContent(json));
return await response.Content.ReadAsStringAsync();
}
}
The issue is that I get a series of errors during await _api.ChargeCard(token, 5.00M):
The first exception happens during authorizationKey = await client.GetStringAsync(Url); the exception message is the following:
{System.Net.Http.HttpRequestException: 404 (Not Found) at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x0000a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.2.0.11/src/mono/mcs/class/System.Net.Http/System.Net.Http/HttpResponseM…}
I get another exception during response = await client.PostAsync("/api/Stripe", new StringContent(json));
{System.InvalidOperationException: The request URI must either be an absolute URI or BaseAddress must be set at System.Net.Http.HttpClient.SendAsync (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Thr…}
The third exception happens at the catch block of the viewModel.ProcessPayment() method:
{System.NullReferenceException: Object reference not set to an instance of an object at Zwaby.Services.APIRepository+d__3.MoveNext () [0x00184] in /Users/carlos/Projects/Zwaby/Zwaby/Services/APIRepository.cs:57 --- End of stack trace from previou…}
In my Web API project, I have a StripeController, but my implementation may not be fully correct:
[Route("api/Stripe")]
public class StripeController : Controller
{
private readonly StripeContext _context;
public StripeController(StripeContext context)
{
_context = context;
if (_context.StripeCharges.Count() == 0)
{
_context.StripeCharges.Add(new StripeItem { });
_context.SaveChanges();
}
}
[HttpGet]
public IActionResult Get(string key)
{
// TODO: implement method that returns authorization key
}
[HttpPost]
public IActionResult Charge(string stripeToken, decimal amount)
{
var customers = new StripeCustomerService();
var charges = new StripeChargeService();
var customer = customers.Create(new StripeCustomerCreateOptions
{
SourceToken = stripeToken
});
var charge = charges.Create(new StripeChargeCreateOptions
{
Amount = (int)amount,
Description = "Sample Charge",
Currency = "usd",
CustomerId = customer.Id
});
return View();
}
}
For completeness, I am including the StripeRepository class, the other parameter of the PaymentPageViewModel:
public class StripeRepository: IStripeRepository
{
public string CreateToken(string cardNumber, string cardExpMonth, string cardExpYear, string cardCVC)
{
StripeConfiguration.SetApiKey("my_test_key");
//TODO: Wireup card information below
var tokenOptions = new StripeTokenCreateOptions()
{
Card = new StripeCreditCardOptions()
{
Number = "4242424242424242",
ExpirationYear = 2018,
ExpirationMonth = 10,
Cvc = "123"
}
};
var tokenService = new StripeTokenService();
StripeToken stripeToken = tokenService.Create(tokenOptions);
return stripeToken.Id;
}
}
Thank you so much!

ASP.net client and ODataController issues

I have an ODataController with 2 methods:
[EnableQuery]
public SingleResult<item> Getitem([FromODataUri] System.Guid key)
{
return SingleResult.Create(db.items.Where(item=> item.guid == key));
}
public async Task<IHttpActionResult> Postitem([FromODataUri] System.Guid key, [FromBody] double itemId)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//Find the correct account
item i = await db.items.FirstAsync(item=> item.guid == key);
if (i == null)
{
return NotFound();
}
//Update the account field we are using for id
i.itemId = itemId;
//Save the changes
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!itemExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(i);
}
private bool itemExists(System.Guid key)
{
return db.items.Count(e => e.guid == key) > 0;
}
With the standard WebApiConfig:
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.EnableCors();
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<item>("items");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
And I can type mydomain.com/odata/items(guid'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX') in the url bar and get the database object as json just fine.
But when I try the following client code:
var itemGuid = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
var itemId = "55555";
using (WebClient wc = new WebClient())
{
wc.UseDefaultCredentials = true;
var domain = "mydomain.com";
var url = domain + "/odata/items(guid'" + itemGuid + "')";
var data = new NameValueCollection();
data["itemId"] = itemId;
byte[] temp = wc.UploadValues(url, "POST", data);
context.Response.Write(Encoding.UTF8.GetString(temp));
}
I get The remote server returned an error: (404) Not Found.
I know it's probably some simple mistake, but been messing around with it too long and I'm new to asp.net.
I think I may have figured it out and it makes sense. So if you create an OdataController you sorta just have your default Post to create a new item, Patch to change/update an update, Put to replace an item with a new one...
Then if you want custom api calls you need to use actions: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/odata-actions
So I was just doing it all wrong. I just assumed you could put Post in front of some function name and it would be a Post opperation with custom arguments.

Resources