I'm using .NET and Stripe to make a webshop, and I'm trying to figure out how to redirect a customer to a success page, once the charge has been successfull. However Stripe recently changed their API, and I've been unable to find any resources online explaining how to do this.
I've tried creating a webhook that listens to the charge.succeeded event, and I can get the event to trigger, but I'm unable to redirect the customer to any page from the webhook.
Another thing I've tried is in the checkout page where I've added method="post" to the form, and type="submit" and formmethod="post" to the button respectively, so that when the customer clicks "Pay," the customer is redirected through the post method of the checkout page, but I can't get the post method to run.
Checkout razor page:
<head>
<title>Checkout</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<--! This is where I've tried method="post", type="submit" and formmethod="post" -->
<form id="payment-form">
<div id="card-element">
<!-- Elements will create input elements here -->
</div>
<!-- We'll put the error messages in this element -->
<div id="card-errors" role="alert"></div>
<button id="submit">Pay</button>
</form>
#section scripts{
<script>
// Set your publishable key: remember to change this to your live publishable key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = Stripe('{PUBLIC KEY}');
var elements = stripe.elements();
window.onload = function () {
// Set up Stripe.js and Elements to use in checkout form
var style = {
base: {
color: "#32325d",
}
};
var card = elements.create("card", { style: style });
card.mount("#card-element");
card.addEventListener('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (ev) {
ev.preventDefault();
stripe.confirmCardPayment('#Model.ClientSecret', {
payment_method: {
card: card,
billing_details: {
name: '#Model.CustomerInformation.FirstName',
email: '#Model.CustomerInformation.Email',
address: {
city: '#Model.CustomerInformation.City',
line1: '#Model.CustomerInformation.Address1',
postal_code: '#Model.CustomerInformation.ZipCode'
}
}
}
}).then(function (result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
}
}
});
});
};
</script>
Webhook:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Stripe;
namespace workspace.Controllers
{
[Route("api/[controller]")]
public class StripeWebHook : Controller
{
// If you are testing your webhook locally with the Stripe CLI you
// can find the endpoint's secret by running `stripe listen`
// Otherwise, find your endpoint's secret in your webhook settings in the Developer Dashboard
const string endpointSecret = "ENDPOINT SECRET";
[HttpPost]
public async Task<IActionResult> Index()
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
try
{
var stripeEvent = EventUtility.ParseEvent(json);
// Handle the event
if (stripeEvent.Type == Events.PaymentIntentSucceeded)
{
var paymentIntent = stripeEvent.Data.Object as PaymentIntent;
Console.WriteLine("Successful!");
return Ok();
}
else if (stripeEvent.Type == Events.ChargeSucceeded)
{
Console.WriteLine("Successful!");
// This is where I've tried return RedirectToPage("/Index");
return Ok();
}
else if (stripeEvent.Type == Events.PaymentIntentCreated)
{
Console.WriteLine("Successful!");
return Ok();
}
else if (stripeEvent.Type == Events.PaymentMethodAttached)
{
var paymentMethod = stripeEvent.Data.Object as PaymentMethod;
Console.WriteLine("PaymentMethod was attached to a Customer!");
}
// ... handle other event types
else
{
// Unexpected event type
return BadRequest();
}
return Ok();
}
catch (StripeException e)
{
return BadRequest();
}
}
}
}
I think that we should iron out a few concepts here first. The webhook endpoint is a standalone API that lives in your system somewhere and reacts to Events that are posted to it from Stripe, such as the charge.succeeded Event.
Your Elements implementation in the browser is completely separate and can't respond to anything that your webhook endpoint can return in terms of HTTP codes (redirects and such).
To answer your core question directly, in the Javascript in the else block where it says that the payment was successfully processed, you can call [0]
location.href = "https://your-success-page.com"
... to send the user to a success page. The reason that the form won't submit is because the submit event of the form has been prevented with ev.preventDefault();.
This whole flow is documented in detail here [1][2].
Hope this helps!
[0] https://developer.mozilla.org/en-US/docs/Web/API/Window/location
[1] https://stripe.com/docs/payments/accept-a-payment
[2] https://stripe.com/docs/webhooks
Related
Some of my controller methods have the [ValidateAntiForgeryToken] attribute for the usual reasons. It's only app-internal actions, no cross-site API or similar. Now I replaced a request made from JavaScript from jQuery (which seems to send data as form fields) with a real JSON post using fetch() directly. The __RequestVerificationToken field was among the sent data so it must have ended up in a place where ASP.NET Core MVC was looking for it.
Now it's in the JSON body, there are no form fields anymore. And the request fails with code 400, probably due to the missing (not found) token.
I've searched for solutions but this has so far only been covered for the older non-Core ASP.NET from 10 years ago. Is it still possible today with current tools to send the token in the JSON body or as HTTP header (I'm fine with either one) and have it validated without much boilerplate code? I can add a special attribute class for that if needed. I already looked at the framework class but it doesn't do anything, this must be handled elsewhere.
Below is a work demo, you can refer to it. Read this to know more.
1.Customize AntiforgeryOptions in Program.cs:
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
});
2.Require antiforgery validation
public IActionResult Index()
{
// ...
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Privacy()
{
// ...
return View();
}
Index.cshtml:
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
#{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="#requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
#section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("#Url.Action("Privacy")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
result:
I would like to implement a welcome message for every members added based on their locale. The code is as following:
if (message.Type == ActivityTypes.ConversationUpdate)
{
// some code...
if (message.Locale == "en-us")
{
var reply = message.CreateReply("Hello world");
}
else
{
// some code...
}
// some code...
}
Strangely, the locale is null even though I've set the locale both when I test it using bot emulator and BotFramework-WebChat. The locale property is working fine when messages is received.
Is there any way I could get the locale during conversationUpdate activity?
Thank you in advance!
One solution to get the language of the user before his 1st input is to use the backchannel feature of the Webchat. This allows us to push information to our bot in a hidden way, to provide locale or a custom id for example.
You will found this demo on GitHub account here.
In particular, here is the sample of integration of your webchat sending the event to the bot at the end with a postActivity, created from the samples on Microsoft's Webchat GitHub description:
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet" />
</head>
<body>
<div id="bot" />
<script src="https://cdn.botframework.com/botframework-webchat/latest/botchat.js"></script>
<script>
// Get parameters from query
const params = BotChat.queryParams(location.search);
// Language definition
var chatLocale = params['locale'] || window.navigator.language;
// Connection settings
const botConnectionSettings = new BotChat.DirectLine({
domain: params['domain'],
secret: 'YOUR_SECRET',
webSocket: params['webSocket'] && params['webSocket'] === 'true' // defaults to true
});
// Webchat init
BotChat.App({
botConnection: botConnectionSettings,
user: { id: 'userid' },
bot: { id: 'botid' },
locale: chatLocale,
resize: 'detect'
}, document.getElementById('bot'));
// Send message to provide language of user
botConnectionSettings.postActivity({
type: 'event',
from: { id: 'userid' },
locale: chatLocale,
name: 'localeSelectionEvent',
value: chatLocale
}).subscribe(function (id) { console.log('event language "' + chatLocale + '" selection sent'); });
</script>
</body>
</html>
I added a console event to show the activity posted.
This event is then received by the bot's MessageController and treated:
[BotAuthentication]
public class MessagesController : ApiController
{
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
// DEMO PURPOSE: echo all incoming activities
Activity reply = activity.CreateReply(Newtonsoft.Json.JsonConvert.SerializeObject(activity, Newtonsoft.Json.Formatting.None));
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
connector.Conversations.SendToConversation(reply);
// Process each activity
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
// Webchat: getting an "event" activity for our js code
else if (activity.Type == ActivityTypes.Event && activity.ChannelId == "webchat")
{
var receivedEvent = activity.AsEventActivity();
if ("localeSelectionEvent".Equals(receivedEvent.Name, StringComparison.InvariantCultureIgnoreCase))
{
await EchoLocaleAsync(activity, activity.Locale);
}
}
// Sample for emulator, to debug locales
else if (activity.Type == ActivityTypes.ConversationUpdate && activity.ChannelId == "emulator")
{
foreach (var userAdded in activity.MembersAdded)
{
if (userAdded.Id == activity.From.Id)
{
await EchoLocaleAsync(activity, "fr-FR");
}
}
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private async Task EchoLocaleAsync(Activity activity, string inputLocale)
{
Activity reply = activity.CreateReply($"User locale is {inputLocale}, you should use this language for further treatment");
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.SendToConversationAsync(reply);
}
}
Illustration de l'arrivée des messages :
For French speaking users, here is a more detailed answer on my company's blog
With DirectLineJs 0.13.0, a property has been added that allows to specify the start locale like this:
...
createDirectLine({
token: tokenResponse.token,
domain: `https://europe.directline.botframework.com/v3/directline`,
pollingInterval: 500,
conversationStartProperties: {
locale : "fr"
},
watermark: "-",
})
I am new to MVC and trying to pass the last created Id (once the save button has been clicked in the form).
Can anyone please tell me if it is possible to pass this value to the toastr display, and how this can be done, so once the save button is pressed it returns that Id number?
Additionally to my comment, here's a more complex answer.
Roughly it contains the following items:
Views: CreateItem, NewItemHandler
Controllers: ItemHandler
Javascript: site.js and jQuery
The CreateItem view is the dialog where the user enters their item values. In my case a simple form with two input fields and the mandatory submit button.
#{
ViewBag.Title = "CreateItem";
}
<h2>CreateItem</h2>
<form id="newItemForm">
Item name: <input id="itemname" type="text" name="fname"><br>
Item weight: <input id="itemweight" type="text" name="lname"><br>
<input type="submit" value="Submit">
</form>
The JavaScript should stop the redirection when clicking on submit, this is done by returning false within $("newItemForm").submit(...). Furthermore we no need to tell the server that it needs to create our item, so we have to create our own submit request, which I did with jQuery.post():
$('#newItemForm').submit(function () {
sendPostAndShowResult();
return false;
});
function sendPostAndShowResult() {
var name = $("#itemname").text();
var weight = $("#itemweight").text();
$.post("/Item/NewItemHandler",
{ "name": name, "weight": weight }
).done(function (data) {
alert("The ID of your new item is: " + $.trim(data)); //replace with toast
})
.fail(function () {
alert("Error while processing the request!");
});
}
Just a hint: I didn't use toast here, since I never used it, but I guess it shouldn't be too difficult to adapt.
The final piece of the puzzle is the NewItemHandler, which creates the item, figures out the ID and returns the value:
The View is quite easy. Since we don't need a Layout, it has been set to "".
#{
Layout = "";
}
#Html.Raw(Session["ItemID"])
As you see, we just need to get the "ItemID" into our Session object, this is done by the Controller.
[HttpPost]
public ActionResult NewItemHandler(string name, string weight)
{
int id = GenerateNewItem(name, weight);
Session["ItemID"] = id;
return View();
}
EDIT: I tried to adapt this approach to your solution:
You need to remove the return RedirectToAction() with return View(); in your Controller. This then returns (Save.cshtml) a response, with the ID in an ohterwise empty file (Layout = "").
Your Save.cshtml is empty I guess, so replace it with
#{
Layout = "";
}
#Html.Raw(Session["ItemID"])
In your controller the Save Method should look remotely like this.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(BidstonHwrc bidstonhwrc)
{
_context.BidstonHwrc.Add(bidstonhwrc);
try
{
_context.SaveChanges(); //either all changes are made or none at all
}
catch (Exception e)
{
Console.WriteLine(e);
}
int id = bidstonhwrc.Id;
Session["ItemID"] = id;
return View();
}
In your MCN Form you need to give your <form> tag an ID, via Razor:
#using (Html.BeginForm("Save", "BidstonHwrc",FormMethod.Post, new { id = "SaveBidstonHwrc" }))
The javascript code should look like this, simply adapt the IDs:
$('#SaveBidstonHwrc').submit(function () {
sendPostAndShowResult();
return false;
});
function sendPostAndShowResult() {
//foreach Model/ViewModel Property one line e.g.
var Id = $("Id").text();
var McnNumber = $("McnNumber").text();
$.post("/BidstonHwrc/Save",
{ "Id": Id, "McnNumber": McnNumber }
).done(function (data) {
alert("The ID of your new item is: " + $.trim(data)); //replace with toast
$(location).attr('href', '/Home/Index') //Redirect to Home
})
.fail(function () {
alert("Error while processing the request!");
});
}
I uploaded a project that should represent your solution a bit.
You can download it here (28MB): Project download
I'm using PayPal express checkout (checkout.js V4.0.0) with asp.net mvc to allow a user to pay for data transactions. What I need to do when the express checkout button is clicked is perform some checks on the database and confirm that PayPal can proceed (this is also time related, as the database could be in a locked processing state).
I've setup the Advanced Server Integration and I then call the create-payment controller from the payment section in paypal.Button.render, but this expects a json object with a PaymentID element to be returned. At what point am I able to perform these checks on server side and abort from the paypal process if PayPal can't continue? If a check fails, the server side also needs to return an appropriate error page or message to be displayed.
This is the paypal button code:
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
paypal.Button.render({
env: 'sandbox',
payment: function (resolve, reject) {
var CREATE_PAYMENT_URL = '#Url.Action("PayTransactions","Pending")';
paypal.request.post(CREATE_PAYMENT_URL)
.then(function (data) { resolve(data.paymentID); })
.catch(function (err) { reject(err); });
},
onAuthorize: function(data) {
var EXECUTE_PAYMENT_URL = 'https://my-store.com/paypal/execute-payment';
paypal.request.post(EXECUTE_PAYMENT_URL,
{
paymentID: data.paymentID,
payerID: data.payerID
})
.then(function(data) { /* Go to a success page */ })
.catch(function (err) { /* Go to an error page */ });
},
onCancel: function (data, actions) {
return actions.redirect();
},
onError: function (err) {
// Show an error page here, when an error occurs
}
}, '#paypal-button');
</script>
which at the payment section calls this:
public async Task<string> PayTransactions()
{
// check if payment is still necessary or end of month is running
var condition = await CheckDatabaseIsUsable();
switch (condition)
{
case 1:
ModelState.AddModelError("error", "some error message");
return RedirectToAction("Index", "Pending");
case 2:
ModelState.AddModelError("error", "some other error");
return RedirectToAction("Index", "Pending");
}
var paypalPayment = FormPayPalPaymentObject();
return JsonConvert.SerializeObject(new { paymentID = paypalPayment.PaymentId });
}
The problem is that I am now mixing the ActionResult and json string return types.
You can return json also for the redirection responses and control with javascript when it is a redirection or and ok response.
Server side:
return JsonConvert.SerializeObject(new { redirect= Url.Action("Index", "Pending") });
Javascript:
paypal.request.post(CREATE_PAYMENT_URL)
.then(function (data) {
if(data.redirect)
{
//cancel the flow and redirect if needed
window.location.href = data.redirect;
}else{
resolve(data.paymentID);
}
})
.catch(function (err) { reject(err); });
},
Using an IActionResult object as the return value for the PayTransactions is preferable
public async Task<IActionResult> PayTransactions()
{
...
return Json(new { paymentID = paypalPayment.PaymentId });
}
Also consider that the modelstate errors you are adding are useless because of the redirection.
You can call reject(error) to cancel the payment.
My goal is to use the FB login button so that FB users can log into my ASP.NET MVC 3 website. It seems that things have changed recently with the Facebook C# SDK and all the old examples will not work with the new version. I've tried for a day to get them to work... I'm working off of the tutorial Getting Started with the Facebook C# SDK for ASP.NET
Currently when I browse to http://localhost:8033/ it seems to automatically log me in (even after a fresh restart of Chrome) because it shows "my-name uses my-app-name" and shows my picture. I expected it to instead show a FB login button. And when I go to http://localhost:8033/Home/About I get an error that Session["AccessToken"] is null (which makes sense because it's clearly not getting set).
Here's what I have:
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Facebook;
namespace FacebookTest.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);
dynamic result = client.Get("me", new { fields = "name,id" });
string name = result.name;
string id = result.id;
ViewBag.Message = "Hello id: " + id;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FacebookLogin(HttpContext context)
{
var accessToken = context.Request["accessToken"];
context.Session["AccessToken"] = accessToken;
return RedirectToAction("About");
}
}
}
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit http://asp.net/mvc.
</p>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
//appId: 'YOUR_APP_ID', // App ID
appId: '<MY-NUMBER-REMOVED>', // App ID
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
// Additional initialization code here
FB.Event.subscribe('auth.authResponseChange', function (response) {
if (response.status === 'connected') {
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
// TODO: Handle the access token
// Do a post to the server to finish the logon
// This is a form post since we don't want to use AJAX
var form = document.createElement("form");
form.setAttribute("method", 'post');
//form.setAttribute("action", '/FacebookLogin.ashx');
form.setAttribute("action", '/Home/FacebookLogin');
var field = document.createElement("input");
field.setAttribute("type", "hidden");
field.setAttribute("name", 'accessToken');
field.setAttribute("value", accessToken);
form.appendChild(field);
document.body.appendChild(form);
form.submit();
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
} else {
// the user isn't logged in to Facebook.
}
});
};
// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
} (document));
</script>
<div class="fb-login-button" data-show-faces="true" data-width="400" data-max-rows="1"></div>
About.cshtml
#{
ViewBag.Title = "About Us";
}
<h2>About</h2>
<p>
#ViewBag.Message
</p>
Can you tell me how to fix this so that a FB login button is displayed, and when clicked it asks the users to do a FB authentication, sends them back, and then my app recognizes them as a logged in user?
As for the Login button, if you are logged in to Facebook prior to visiting your app you will see the faces instead of the login button, the only way to get the Login button back is to go to facebook.com and do a logout or possibly do a facebook logout using the C# SDK. Depending on your requirements this may or may not be what you wanted. There is a bit about Re-Authentication in the SDK documentation if that is what you really want.
I've tweaked your app by removing the submit() and replaced it with an ajax post, The FacebookLogin action was changed and I added some error handling on the About action. Your original app will work but it will automatically redirect to About if you are logged in to Facebook.
Update Added a login link which does not use Javascript, insert appid and appsecret and adjust portnumber accordingly. This was adapted from the server side login sample found here which is far prettier than this code :)
Note The state value being passed in the server side flow should be a unqiue value that you should validate in the ConnectResponse() method, i.e. generate a value in FacebookLoginNoJs and make sure it's the same in ConnectResponse to prevent cross site request forgery
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Facebook;
namespace FacebookTest.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
ViewBag.Message = "Please log in first";
if (Session["AccessToken"] != null)
{
var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);
try
{
dynamic result = client.Get("me", new { fields = "name,id" });
string name = result.name;
string id = result.id;
ViewBag.Message = "Hello id: " + id + " aka " + name;
}
catch (FacebookOAuthException x)
{
}
}
return View();
}
public void FacebookLogin(string uid, string accessToken)
{
var context = this.HttpContext;
context.Session["AccessToken"] = accessToken;
}
public ActionResult FacebookLoginNoJs()
{
return Redirect("https://www.facebook.com/dialog/oauth?client_id=MY-APPID-REMOVED&redirect_uri=http://localhost:45400/Home/ConnectResponse&state=secret");
}
public ActionResult ConnectResponse(string state, string code, string error, string error_reason, string error_description, string access_token, string expires)
{
if (string.IsNullOrEmpty(error))
{
try
{
var client = new FacebookClient();
dynamic result = client.Post("oauth/access_token",
new
{
client_id = "MY-APPID-REMOVED",
client_secret = "MY-APP-SECRET-REMOVED",
redirect_uri = "http://localhost:45400/Home/ConnectResponse",
code = code
});
Session["AccessToken"] = result.access_token;
if (result.ContainsKey("expires"))
Session["ExpiresIn"] = DateTime.Now.AddSeconds(result.expires);
}
catch
{
// handle errors
}
}
else
{
// Declined, check error
}
return RedirectToAction("Index");
}
}
}
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit http://asp.net/mvc.
</p>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
//appId: 'YOUR_APP_ID', // App ID
appId: 'MY-APPID-REMOVED', // App ID
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
// Additional initialization code here
FB.Event.subscribe('auth.authResponseChange', function (response) {
if (response.status === 'connected') {
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
var url = '/Home/FacebookLogin';
$.post(url, { uid: uid, accessToken: accessToken }, function (data) {
});
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
} else {
// the user isn't logged in to Facebook.
}
});
};
// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
} (document));
</script>
<div class="fb-login-button" data-show-faces="true" data-width="400" data-max-rows="1"></div>
#Html.ActionLink("The NoJs Login", "FacebookLoginNoJs", "Home")
About.cshtml
#{
ViewBag.Title = "About Us";
}
<h2>About</h2>
<p>
#ViewBag.Message
</p>