I am trying to implement PayPal to my web app.
The very first time PayPal payment works fine!
But if I try second time, it fails. Can I only test once???
When PayPal succeeds I see this link:
https://localhost:44333/Paypal/PaymentWithPayPal?guid=94987&paymentId=PAY-1DM32358RW0519317LDPKCYY&token=EC-1G993722W11620224&PayerID=8QXDDJEKRZKZW
When PayPal fails I see this link:
https://localhost:44333/Paypal/PaymentWithPayPal?guid=52246&paymentId=PAY-9V465873R0219235GLDPKDNA&token=EC-1F105391KF572764B&PayerID=8QXDDJEKRZKZW
This is my PayPalController:
public class PayPalController : Controller
{
[Authorize]
// GET: PayPal
public ActionResult Index()
{
return View();
}
public ActionResult PaymentWithPaypal()
{
//getting the apiContext as earlier
APIContext apiContext = Configuration.GetAPIContext();
try
{
string payerId = Request.Params["PayerID"];
if (string.IsNullOrEmpty(payerId))
{
//this section will be executed first because PayerID doesn't exist
//it is returned by the create function call of the payment class
// Creating a payment
// baseURL is the url on which paypal sendsback the data.
// So we have provided URL of this controller only
string baseURI = Request.Url.Scheme + "://" + Request.Url.Authority +
"/Paypal/PaymentWithPayPal?";
//guid we are generating for storing the paymentID received in session
//after calling the create function and it is used in the payment execution
var guid = Convert.ToString((new Random()).Next(100000));
//CreatePayment function gives us the payment approval url
//on which payer is redirected for paypal account payment
var createdPayment = this.CreatePayment(apiContext, baseURI + "guid=" + guid);
//get links returned from paypal in response to Create function call
var links = createdPayment.links.GetEnumerator();
string paypalRedirectUrl = null;
while (links.MoveNext())
{
Links lnk = links.Current;
if (lnk.rel.ToLower().Trim().Equals("approval_url"))
{
//saving the payapalredirect URL to which user will be redirected for payment
paypalRedirectUrl = lnk.href;
}
}
// saving the paymentID in the key guid
Session.Add(guid, createdPayment.id);
return Redirect(paypalRedirectUrl);
}
else
{
// This section is executed when we have received all the payments parameters
// from the previous call to the function Create
// Executing a payment
var guid = Request.Params["guid"];
var executedPayment = ExecutePayment(apiContext, payerId, Session[guid] as string);
if (executedPayment.state.ToLower() != "approved")
{
return View("FailureView");
}
}
}
catch (Exception ex)
{
Logger.Log("Error" + ex.Message);
return View("FailureView");
}
return View("SuccessView");
}
private PayPal.Api.Payment payment;
private Payment ExecutePayment(APIContext apiContext, string payerId, string paymentId)
{
var paymentExecution = new PaymentExecution() { payer_id = payerId };
this.payment = new Payment() { id = paymentId };
return this.payment.Execute(apiContext, paymentExecution);
}
private Payment CreatePayment(APIContext apiContext, string redirectUrl)
{
var userId = User.Identity.GetUserId();
var userEmail = User.Identity.GetUserName();
//similar to credit card create itemlist and add item objects to it
var itemList = new ItemList() { items = new List<Item>() };
itemList.items.Add(new Item()
{
name = "Premium Monthly $99.00",
currency = "USD",
price = "99",
quantity = "1",
description = userEmail + " Pays Premium Monthly $99.00 on " + DateTime.Now.ToString("F")
});
var payer = new Payer() { payment_method = "paypal" };
// Configure Redirect Urls here with RedirectUrls object
var redirUrls = new RedirectUrls()
{
cancel_url = redirectUrl,
return_url = redirectUrl
};
// similar as we did for credit card, do here and create details object
var details = new Details()
{
subtotal = "99.00"
};
// similar as we did for credit card, do here and create amount object
var amount = new Amount()
{
currency = "USD",
total = "99.00", // Total must be equal to sum of shipping, tax and subtotal.
details = details
};
var transactionList = new List<Transaction>();
transactionList.Add(new Transaction()
{
description = userEmail + "Paid Premium Monthly $99.00 on " + DateTime.Now.ToString("F"),
invoice_number = "890918",
amount = amount,
item_list = itemList
});
this.payment = new Payment()
{
intent = "sale",
payer = payer,
transactions = transactionList,
redirect_urls = redirUrls
};
// Create a payment using a APIContext
return this.payment.Create(apiContext);
}
}
Please help!
Related
This is my RestClientService :
public class RestClientService : IRestClientService
{
protected readonly RestClient _restClient;
protected readonly RestRequest _restRequest;
public RestClientService()
{
_restClient = new RestClient();
_restRequest = new RestRequest();
}
public async Task<MessageDTO> SendComment(Websites website, Comment comment, int postId)
{
if (await IsPostExist(postId,website))
{
_restClient.Options.BaseUrl = new Uri($"{website.Url}/wp-json/wp/v2/comments/");
_restRequest.Method = Method.Post;
_restRequest.RequestFormat = DataFormat.Json;
_restRequest.AddJsonBody(new
{
post = postId,
author_name = comment.Author,
content = comment.Body
});
var result = await _restClient.ExecuteAsync(_restRequest);
return new MessageDTO
{
Message = result.Content,
Status = result.StatusCode.ToString()
};
}
return new MessageDTO
{
Message = "Post Not Found",
Status = "404"
};
}
}
I have a list of comments and list of products that I iterate over them and call SendComment method from RestClientService class. The problem is in first time SendComment method called _restRequest object will be get JsonBody and everything is okay but next time this method calls in loop _restRequest object has old data and won't be renewed.
In DI Container I added (Transient) RestClientService
builder.Services.AddTransient<IRestClientService,RestClientService>();
Here is where I used SendComment method in another service.
public async Task<MessageDTO> CreateSendCommentJob(SendCommentConfiguration config)
{
var updatedConfig = await _sendCommentConfigurationRepository.Get(config.Id);
var ConfigDetails = JsonConvert.DeserializeObject<SendCommentConfigurationDetailsDTO>(updatedConfig.Configuration);
var mappedWebsite = _mapper.Map<Websites>(ConfigDetails.WebsiteInfo);
if (ConfigDetails.CommentType == "blog")
{
var comments = await _uCommentService.GetCommentsByGroupId(ConfigDetails.CommentGroupId);
var commentCount = 0;
for (int postCount = 0; postCount < ConfigDetails.ProductPerSendCount; postCount++)
{
var postId = ConfigDetails.Ids[postCount];
while (commentCount < ConfigDetails.CommentsPerProductCount)
{
var random = new Random();
var index = random.Next(comments.Count);
var result = await _restClientService.SendComment(mappedWebsite, comments[index], postId);
if (result.Status == "Created")
{
Console.WriteLine($"Comment Index ({index}) at Id ({postId}) submited successfuly...");
commentCount++;
}
else
{
Console.WriteLine($"{postId} - {result.Status} - {result.Message}");
}
}
ConfigDetails.Ids.Remove(postId);
commentCount = 0;
}
}
var newConfig = new SendCommentConfiguration
{
Id = config.Id,
Configuration = JsonConvert.SerializeObject(ConfigDetails)
};
await _sendCommentConfigurationRepository.Edit(newConfig);
return new MessageDTO
{
Status = "200",
Message = "Comments Successfuly Sent "
};
}
_restClientService.SendComment is called in a loop on the same service instance. As the request instance is a field of the service instance, the same request instance is reused for each call.
As each apple performs a distinct request, each request must use a distinct instance of RestRequest, like :
public class RestClientService : IRestClientService
{
public async Task<MessageDTO> SendComment(Websites website, Comment comment, int postId)
{
if (await IsPostExist(postId,website))
{
//Each call, new instances
var restClient = new RestClient();
var restRequest = new RestRequest();
restClient.Options.BaseUrl = new Uri($"{website.Url}/wp-json/wp/v2/comments/");
restRequest.Method = Method.Post;
restRequest.RequestFormat = DataFormat.Json;
restRequest.AddJsonBody(new
{
post = postId,
author_name = comment.Author,
content = comment.Body
});
var result = await restClient.ExecuteAsync(_restRequest);
return new MessageDTO
{
Message = result.Content,
Status = result.StatusCode.ToString()
};
}
return new MessageDTO
{
Message = "Post Not Found",
Status = "404"
};
}
}
I want to create help pages for ASP.NET Web API.
I created a new ASP.NET Web application project and select the Web API project template. It added Areas/HelpPage.
When I run the application, the home page contains a link to the API help page. From the home page, the relative path is /Help. It shows ValuesController action, but when I add another controller, the help page doesn't show that controller and any of its actions.
public class CalendarController : ApiController
{
private readonly string siteUrl = ConfigurationManager.AppSettings["SiteUrl"];
private readonly CalendarService calendarService;
public CalendarController()
{
calendarService = new CalendarService();
}
[HttpPost]
public async Task<ResponseModel<List<ApiCalendarViewModel>>> Paging(JObject param)
{
try
{
var startIndex = Convert.ToInt32(param["StartIndex"]);
var pageSize = Convert.ToInt32(param["PageSize"]);
var CalendarList = await calendarService.SelectAllAsync(startIndex, pageSize);
var list = CalendarList.Select(m => new ApiCalendarViewModel()
{
Author = m.Author,
Date = PersianDateTime.ToLongDateWithDayString(m.CreatedDate),
Excerpt = m.Excerpt,
Id = m.Id,
MainImage = siteUrl + m.Image,
Title = m.Title,
StartYear = m.StartYear,
EndYear = m.EndYear,
Semester = m.Semester.GetDisplayName()
}).ToList();
return new ResponseModel<List<ApiCalendarViewModel>>()
{
IsSuccess = true,
Data = list
};
}
catch (Exception e)
{
return new ResponseModel<List<ApiCalendarViewModel>>()
{
IsSuccess = false,
Message = e.Message
};
}
}
[HttpGet]
public async Task<ResponseModel<List<ApiCalendarViewModel>>> GetAll()
{
try
{
var CalendarList = await calendarService.SelectAllAsync();
var list = CalendarList.Select(m => new ApiCalendarViewModel()
{
Author = m.Author,
Date = PersianDateTime.ToLongDateWithDayString(m.CreatedDate),
Excerpt = m.Excerpt,
Id = m.Id,
MainImage = siteUrl + m.Image,
Title = m.Title,
StartYear = m.StartYear,
EndYear = m.EndYear,
Semester = m.Semester.GetDisplayName()
}).ToList();
return new ResponseModel<List<ApiCalendarViewModel>>()
{
IsSuccess = true,
Data = list
};
}
catch (Exception e)
{
return new ResponseModel<List<ApiCalendarViewModel>>()
{
IsSuccess = false,
Message = e.Message
};
}
}
}
how can I get a response after I created a data? So I want is when is saves. it show it's response, maybe in messagebox? Is it possible do it?
This is my controller code in saving..
[HttpPost]
[ValidateAntiForgeryToken]
public async System.Threading.Tasks.Task<ActionResult> Create(FormCollection formCollection, string fn, string ln , ParentModel apsp)
{
string username = "sa";
string apiKey = "sa";
string baseUrl = "https://sandbox-api.paysimple.com";
var settings = new PaySimpleSdk.Models.PaySimpleSettings(apiKey, username, baseUrl);
var paymentService = new PaymentService(settings);
fn = apsp.Customer.FirstName;
ln = apsp.Customer.LastName;
string street1 = apsp.Customer.BillingAddress.StreetAddress1;
string street2 = apsp.Customer.BillingAddress.StreetAddress2;
string city = apsp.Customer.BillingAddress.City;
Enum statecode = apsp.Customer.BillingAddress.StateCode;
Enum country = apsp.Customer.BillingAddress.Country;
string zipcode = apsp.Customer.BillingAddress.ZipCode;
string credit = apsp.CreditCard.CreditCardNumber;
string expir = apsp.CreditCard.ExpirationDate;
Enum issuer = apsp.CreditCard.Issuer;
decimal amount = apsp.Payment.Amount;
string ccv = apsp.Payment.Cvv;
var customerPayment = new NewCustomerPayment<CreditCard>
{
Customer = new Customer()
{
FirstName = fn,
LastName = ln,
BillingAddress = new Address
{
StreetAddress1 = street1,
StreetAddress2 = street2,
City = city,
StateCode = (StateCode)statecode,
Country = (CountryCode)country,
ZipCode = zipcode
}
},
Account = new CreditCard
{
CreditCardNumber = credit,
ExpirationDate = expir,
Issuer = (Issuer)issuer
},
Payment = new Payment
{
Amount = amount,
Cvv = ccv
}
};
var newCustomerPayment = await paymentService.CreateNewCustomerPaymentAsync(customerPayment);
return RedirectToAction("Index");
}
The function of creating a data is from the SDK and the model itself
You have 2 options:
Create action should return JsonResult instead of redirect. But you will need to use AJAX when calling Create action.:
public async System.Threading.Tasks.Task<ActionResult> Create(FormCollection formCollection, string fn, string ln , ParentModel apsp)
{
/// your code for creating object
return Json(newCustomerPayment, JsonRequestBehavior.AllowGet);
}
on the client side use Ajax.BeginForm instead of Html.BeginForm
using (Ajax.BeginForm("Create", Home , new AjaxOptions { HttpMethod = "POST", OnSuccess = "customerPaymentCreatedSuccess" }))
{
}
<script>
function customerPaymentCreatedSuccess(response)
{
alert(JSON.stringify(response, null, 4));
}
</script>
Use Post/Redirect/Get pattern. Once new payment is created, store it in TempData
and return redirect as you currently do:
TempData["newCustomerPayment"] = newCustomerPayment;
return RedirectToAction("Index");
Then in Index Action check if there is anything in TempData and if there is, pass it to the view
public ActionResult Index()
{
var customerPayment = TempData["newCustomerPayment"] as NewCustomerPayment;
if(customerPayment != null)
{
ViewBag.customerPayment = customerPayment;
}
//other code..
}
Index view - generate JavaScript code to display customerPayment:
#{var customerPayment = ViewBag.customerPayment as NewCustomerPayment;}
#if(customerPayment != null)
{
<script>
alert("#Html.Raw(JsonConvert.SerializeObject(customerPayment ))");
</script>
}
To show an feedback of your of your operation you could return a JsonResult from your method and make the call and create the message box browser-side via Javascript.
Actions to take
1)change ActionResult to JsonResult in method definition
public async System.Threading.Tasks.Task<JsonResult> Create(FormCollection formCollection, string fn, string ln , ParentModel apsp)
2)change the return to something like:
return this.Json(message)
3)make your call to the method using ajax an create the message box on the callback method
I have made a simple ASP.NET Web API that gets events from a shared google calendar, and serves them to me in json. When i fire it up from localhost i get 104 events returned: but when I've published it to my IIS server, the array contains no elements. I can't debug on it, but i get an empty array presented:
I have made an app on https://console.developers.google.com/ and added both localhost and http://domainname.dk/oauthcallback to it.
My code:
public void GetFixedEvents()
{
const string calendarId = "xxxxxxxxxxxxxxxx#group.calendar.google.com";
try
{
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret,
},
new[] { CalendarService.Scope.Calendar },
"user",
CancellationToken.None).Result;
var service = new CalendarService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest",
});
var queryStart = DateTime.Now;
var queryEnd = queryStart.AddYears(1);
var query = service.Events.List(calendarId);
query.TimeMin = queryStart;
query.TimeMax = queryEnd;
query.SingleEvents = true;
var events = query.Execute().Items;
foreach (var item in events)
{
var tempEvent = new PubEvent
{
Title = item.Summary,
Description = item.Description ?? "None",
Start = item.Start.DateTime,
End = item.End.DateTime,
EventType = item.Summary.Contains("Ladies") ? EventType.LadiesNight : EventType.StudentNight
};
_pubEvents.Add(tempEvent);
}
}
catch (Exception e)
{
Console.WriteLine("Exception encountered: {0}", e.Message);
}
}
Can anyone help? Is it a problem with redirect uri? I have tried adding all the ones I can possibly think of. Is there any way to log the call to the google api?
I have a Web Api project.
I have implemented a custom Authentication Attribute like so:
public class TokenAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// In auth web method you should implement functionality of authentication
// so that client app could be able to get token
if (actionContext.Request.RequestUri.AbsolutePath.Contains("api/auth/login"))
{
return;
}
// Receive token from the client. Here is the example when token is in header:
var token = HttpContext.Current.Request.Headers["Token"];
// Put your secret key into the configuration
var secretKey = ConfigurationManager.AppSettings["JWTSecurityKey"];
try
{
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey);
int separatorIndex = jsonPayload.IndexOf(';');
string userId = "";
DateTime timeIssued = DateTime.MinValue;
if (separatorIndex >= 0)
{
//userId = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(jsonPayload.Substring(0, separatorIndex)));
userId = jsonPayload.Substring(0, separatorIndex);
timeIssued = DateTime.Parse(jsonPayload.Substring(separatorIndex + 1));
}
short TokenTTL = 10;
//try{
//Int16.TryParse(ConfigurationManager.AppSettings["TokenTTL"],TokenTTL);
//}catch(Exception e){ //}
if ((DateTime.Now.Subtract(timeIssued).TotalMinutes >= TokenTTL))
{
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
//Save user in context
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, userId)
};
var id = new ClaimsIdentity(claims, "Basic");
var principal = new ClaimsPrincipal(new[] { id });
actionContext.Request.GetRequestContext().Principal = principal;
}
catch (JWT.SignatureVerificationException)
{
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
}
}
Now how do I get hold of that user in my actionmethod?
[BasicHttpAuthorizeAttribute]
[httpGet]
public void Login()
{
// how do i get user here
}
/////// Save the string username to the context so that I can acess
it in the controler.
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, "john")
};
var id = new ClaimsIdentity(claims, "Basic");
var principal = new ClaimsPrincipal(new[] { id });
actionContext.Request.GetRequestContext().Principal = principal;
// how do i get user here
var name = User.Identity.Name;
BTW, use an authentication filter instead of an authorization filter to perform authentication. See my blog post - http://lbadri.wordpress.com/2014/02/13/basic-authentication-with-asp-net-web-api-using-authentication-filter/.