I get the following error: "message": "Malformed access token - facebook

I have an app in facebook and I am trying to obtain long term token,
for that I call the following link:
https://graph.facebook.com/oauth/authorize?client_id=xxxxxx&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Faccesstokforfacebook%2Ffbaccess&scope=read_stream,read_insights,user_religion_politics,user_relationship_details,user_hometown,user_location,user_likes,user_activities,user_interests,user_education_history,user_work_history,user_website,user_groups,user_events,user_photos,user_videos,user_about_me,user_status,user_games_activity,user_tagged_places,user_actions.books,user_actions.video,user_actions.news
and the return url is a servlet with following codes:
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String accessCode = request.getParameter("code");
System.out.println("dddd "+accessCode);
//print SUCCESS if code is found
/*if (accessCode!=null){*/
out.print("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\"><html><head><title>Facebook Access Granted</title></head><body>");
out.print("<p>SUCCESS!</p><p>"+accessCode+"</p></body></html>");
and this servlet receives the very long code like this:
AQCY244eMOhxEVu3e6UEIl-qK974wTh-p0Il1ZdG9VEAYl5GdrjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxQcJeUmeXFU56cbWbmXJdLQvEyIT7JWCxxu6tChkr9oCL1DVYxxv4v-j4Y_vaWGD7dYcxxxxxxxxxxxxxxxxxxTvZPHLU-tU5ySHrQrVgpo_i8minM73cyWxxxxxxxxxxxxxxdZvnrIhQXQ-B_3LAFzDcWe2NbCW7WSgmQ-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMkJ55M0wHHbLmL4D-g_wLIwhpz4W_8Hz0h7v_ZL
Now when I use this token to get the all info for a page I get an error:
this is a link that I use:
https://graph.facebook.com/v2.0/khalatbari.hooman/feed?access_token=THE ABOVE CODE
and the error is:
Now I think the code that I get is not access token but I have no idea how to use this code to get access token!!!
can anyone help

Finally found solution for Facebook SDK 4.6.0 to getting limited comment's list for feed :
1> Calling commentInfo() firstly Inside Activity's oncreate()
:
private boolean isLoadMoreCalled;
commentInfo("", "true");
2> Putting load more method also there like:
listViewCommentList.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.d("scrollState", ""+scrollState);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int last_visible_in_screen = firstVisibleItem + visibleItemCount;
if(last_visible_in_screen == totalItemCount && isLoadMoreCalled) {
Toast.makeText(getApplicationContext(), "Loading more Items 10", Toast.LENGTH_SHORT).show();
commentInfo(nextFeedUrl, "false");
isLoadMoreCalled = false;
}
}
});
3> create commentInfo() of outside onCreate() :
public void commentInfo (String fields, final String isFirst) {
/** Festival Feed Comments Details #Facebook */
Bundle params = new Bundle();
params.putString("fields", "message,created_time,from");
params.putString("limit", "10");
if(isFirst.equals("false")) {
params.putString("after", fields);
}
showProgressBar();
/* make the API call */
//refreshCurrentAccessTokenAsync();
System.out.println("Acees Token Comment>>>"+ AccessToken.getCurrentAccessToken());
new GraphRequest(AccessToken.getCurrentAccessToken(), "/"+ feedId +"/comments", params, HttpMethod.GET,
new GraphRequest.Callback() {
public void onCompleted(GraphResponse response) {
/* handle the result */
System.out.println("Festival feed Comments response::" + String.valueOf(response.getJSONObject()));
try {
JSONObject jObjResponse = new JSONObject(String.valueOf(response.getJSONObject()));
JSONObject jObjPaging = jObjResponse.getJSONObject("paging");
JSONObject jObjCursor = jObjPaging.getJSONObject("cursors");
nextFeedUrl = "";
nextFeedUrl = jObjCursor.getString("after");
System.out.println("nextFeedUrl>>"+ nextFeedUrl);
JSONArray jArrayData = jObjResponse.getJSONArray("data");
for(int i = 0; i< jArrayData.length(); i++) {
Getting comments info & store into Data-Structure(Array-List)
}
if(isFirst.equals("true")) {
fbFeedCommentAdapter = new FbFeedCommentAdapter();
listViewCommentList.setAdapter(fbFeedCommentAdapter);
}
else {
fbFeedCommentAdapter.notifyDataSetChanged();
}
if(!jObjPaging.has("next")) {
isLoadMoreCalled = false;
}
else {
isLoadMoreCalled = true;
}
dismissProgressBar();
}
catch (Exception e) {
e.printStackTrace();
dismissProgressBar();
}
}
}
).executeAsync();
}
Here,
fbFeedCommentAdapter -> BaseAdapter
listViewCommentList -> Listview
Also refer How to use the Facebook Graph Api Cursor-based Pagination

Related

Call facebook graphrequest multiple times

i'm developpig an app in which i need to call the fb graphrequest multiple times , but those calls needs to be one after the other, the first one will get me the user friends, and the other calls will be done in a loop (for each friend ) get the "likes" that that friend made, now with the code that i made, the first one gives me the friends but the second one (the loop instruction) won't work, i guess it has somehing to do with the async calls but i don't know how to make them serial calls, here's my code :
GraphRequest request = GraphRequest.newMyFriendsRequest(
AccessToken.getCurrentAccessToken(),
new GraphRequest.GraphJSONArrayCallback() {
#Override
public void onCompleted(JSONArray array, GraphResponse response) {
JSONObject jsonArray = response.getJSONObject();
try {
length = jsonArray.getJSONArray("data").length();
for (int i = 0; i < length; i++) {
AlertDialog a = new AlertDialog.Builder(liste_peronalisee.this).create();
a.setTitle("Erreur");
id[i] = jsonArray.getJSONArray("data").getJSONObject(i).getString("id");
a.setMessage(id[i]);
a.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
request.executeAsync();
for(int i=0;i<id.length;i++)
request = GraphRequest.newGraphPathRequest(
AccessToken.getCurrentAccessToken(),
"/".concat(id[i]).concat("/likes"),
new GraphRequest.Callback() {
#Override
public void onCompleted(GraphResponse response) {
JSONObject jsonArray = response.getJSONObject();
try {
length = jsonArray.getJSONArray("data").length();
for (int i = 0; i < length; i++) {
AlertDialog a = new AlertDialog.Builder(liste_peronalisee.this).create();
a.setTitle("Erreur");
id[i] = jsonArray.getJSONArray("data").getJSONObject(i).getString("name");
a.setMessage(id[i]);
a.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
request.executeAsync();
i need a quick answer, thanks in advance

google cloud print from android without dialog

Can someone tell me if it is possible to silently print using google cloud print from an android device?
The goal is that my app grabs a file from a URL or from the SD card and then sends it to a specific printer - all without interaction from anyone looking at the screen or touching anything. It will actually be triggered by a barcode scan on a blue tooth connected device.
Thanks
Well, it is possible but I don't know why there's not too much information about it in the documentation...
The tricky part is connecting to the google cloud print API using only the android device (with no third party servers as the documentation explains here: https://developers.google.com/cloud-print/docs/appDevGuide ), so that's what I'm going to explain.
First, you have to include in your app the Google sign-in API, I recommend firebase API https://firebase.google.com/docs/auth/android/google-signin
Then you have to go to your Google API console: https://console.developers.google.com in the menu, go to Credentials scroll to OAuth 2.0 client IDs select Web client (auto created by Google Service) and save into your project the Client ID and Client secret keys... In my project, I saved them as "gg_client_web_id" and "gg_client_web_secret" as you will see below in the code.
Next, I'm going to paste all the code and then I'll explain it:
public class MainActivity extends AppCompatActivity
implements GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private static final int REQUEST_SINGIN = 1;
private TextView txt;
public static final String TAG = "mysupertag";
public static final String URLBASE = "https://www.google.com/cloudprint/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = (TextView) findViewById(R.id.txt);
mAuth = FirebaseAuth.getInstance();
// Configure Google Sign In
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.gg_client_web_id))
.requestEmail()
.requestServerAuthCode(getString(R.string.gg_client_web_id))
.requestScopes(new Scope("https://www.googleapis.com/auth/cloudprint"))
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
signIn();
}
});
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// ...
}
};
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG, "error connecting: " + connectionResult.getErrorMessage());
Toast.makeText(this, "error CONN", Toast.LENGTH_LONG).show();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == REQUEST_SINGIN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = result.getSignInAccount();
firebaseAuthWithGoogle(account);
} else {
// Google Sign In failed, update UI appropriately
// ...
Toast.makeText(this, "error ", Toast.LENGTH_LONG).show();
}
}
}
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, REQUEST_SINGIN);
}
#Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
#Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
private void firebaseAuthWithGoogle(final GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
FirebaseUser user = task.getResult().getUser();
txt.setText(user.getDisplayName() + "\n" + user.getEmail());//todo
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithCredential", task.getException());
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
getAccess(acct.getServerAuthCode());
}
});
}
private void getPrinters(String token) {
Log.d(TAG, "TOKEN: " + token);
String url = URLBASE + "search";
Ion.with(this)
.load("GET", url)
.addHeader("Authorization", "Bearer " + token)
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
Log.d(TAG, "finished " + result.getHeaders().code() + ": " +
result.getResult());
if (e == null) {
Log.d(TAG, "nice");
} else {
Log.d(TAG, "error");
}
}
});
}
private void getAccess(String code) {
String url = "https://www.googleapis.com/oauth2/v4/token";
Ion.with(this)
.load("POST", url)
.setBodyParameter("client_id", getString(R.string.gg_client_web_id))
.setBodyParameter("client_secret", getString(R.string.gg_client_web_secret))
.setBodyParameter("code", code)
.setBodyParameter("grant_type", "authorization_code")
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
Log.d(TAG, "result: " + result.getResult());
if (e == null) {
try {
JSONObject json = new JSONObject(result.getResult());
getPrinters(json.getString("access_token"));
} catch (JSONException e1) {
e1.printStackTrace();
}
} else {
Log.d(TAG, "error");
}
}
});
}}
As you can see, in the onCreate the important part is creating the GoogleSignInOptions WITH the google cloud print scope AND calling the requestIdToken/requestServerAuthCode methods.
Then in the firebaseAuthWithGoogle method call the getAccess method in order to get the OAuth access token, for making all requests I'm using Ion library: https://github.com/koush/ion
Next with the access_token you can now do requests to the google cloud print API, in this case I call the getPrinters method, in this method I call the "search" method (from google cloud print API) to get all the printers associated to the google account that has signed in.. (to associate a printer to a google account visit this: https://support.google.com/cloudprint/answer/1686197?hl=en&p=mgmt_classic ) Note the .addHeader("Authorization", "Bearer " + token), this is the important part of the request, the "token" var is the access_token, you NEED add this Authorization header in order to use the API and don't forget to refresh when it expires, as explained here : https://developers.google.com/identity/protocols/OAuth2ForDevices in the "Using a refresh token" part.
And that's it, you can now print something sending a POST request to the "submit" method of the google cloud print API, I recommend to go here: https://developers.google.com/cloud-print/docs/appInterfaces and see all the methods available and how to use them (wich parameters send to them, etc). Of course in that link explains the "submit" method too.
EDIT:
EXAMPLE OF HOW TO SEND A REQUEST TO "/submit" FOR PRINTING USING ION LIBRARY AND MJSON LIBRARY (https://bolerio.github.io/mjson/) THE MJSON IS FOR CREATING A JSON OBJECT, YOU CAN CREATE IT THE WAY YOU PREFER
private void printPdf(String pdfPath, String printerId) {
String url = URLBASE + "submit";
Ion.with(this)
.load("POST", url)
.addHeader("Authorization", "Bearer " + YOUR_ACCESS_TOKEN)
.setMultipartParameter("printerid", printerId)
.setMultipartParameter("title", "print test")
.setMultipartParameter("ticket", getTicket())
.setMultipartFile("content", "application/pdf", new File(pdfPath))
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
if (e == null) {
Log.d(TAG, "PRINTTT CODE: " + result.getHeaders().code() +
", RESPONSE: " + result.getResult());
Json j = Json.read(result.getResult());
if (j.at("success").asBoolean()) {
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "ERROR", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(MainActivity.this, "ERROR", Toast.LENGTH_LONG).show();
Log.d(TAG, e.toString());
}
}
});
}
private String getTicket() {
Json ticket = Json.object();
Json print = Json.object();
ticket.set("version", "1.0");
print.set("vendor_ticket_item", Json.array());
print.set("color", Json.object("type", "STANDARD_MONOCHROME"));
print.set("copies", Json.object("copies", 1));
ticket.set("print", print);
return ticket.toString();
}
Yes, You can achieve silent print using this REST API(https://www.google.com/cloudprint/submit) ,I have done it using WCF Service.
you need to download contents from url as base64 content, then add
contentType=dataUrl
in the request.
Here is the code..
postData = "printerid=" + PrinterId;
postData += "&title=" + JobTitle;
postData += "&ticket=" + ticket;
postData += "&content=data:" + documentContent.ContentType + ";base64," + documentContent.Base64Content;
postData += "&contentType=dataUrl";
postData += "&tag=test";
Then , please make a request to submit REST API in this way.
var request = (HttpWebRequest)WebRequest.Create("https://www.google.com/cloudprint/submit");
var data = Encoding.ASCII.GetBytes(postData);
request.Headers.Add("Authorization: Bearer " + Token);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
request.UseDefaultCredentials = true;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
PrintJobResponse printInfo = json_serializer.Deserialize<PrintJobResponse>(responseString);
return printInfo;
Thanks.
For anybody reading this now, after a lot of searching around I have found it is a lot easier and faster to set up to just use Zapier to catch a hook and print to google cloud print (from cordova at least, i can't speak for native apps)

How to Post an Image on Facebook Friend's Wall using Android

I have developed an App in which i am allowing user to post an Image on Friends wall, here i have given only single Static Image, by using below code.
params.putString("picture", FacebookUtility.HACK_ICON_URL);
where HACK_ICON_URL,
It is the URL of an Image...
But now i want to let users to select an image from multiple images and then post on Friends Wall.
FriendsList.java:
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id) {
try {
final long friendId;
friendId = jsonArray.getJSONObject(position).getLong("uid");
String name = jsonArray.getJSONObject(position).getString("name");
new AlertDialog.Builder(this)
.setTitle(R.string.post_on_wall_title)
.setMessage(
String.format(getString(R.string.post_on_wall),
name))
.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
Bundle params = new Bundle();
params.putString("to",
String.valueOf(friendId));
params.putString("caption",
getString(R.string.app_name));
params.putString("description",
getString(R.string.app_desc));
params.putString("link", "http://www.google.com");
params.putString("picture",
FacebookUtility.HACK_ICON_URL);
params.putString("name",
getString(R.string.app_action));
FacebookUtility.facebook
.dialog(FriendsList.this,
"feed",
params,
(DialogListener) new PostDialogListener());
}
}).setNegativeButton(R.string.no, null).show();
} catch (JSONException e) {
showToast("Error: " + e.getMessage());
}
}
public class PostDialogListener extends BaseDialogListener {
#Override
public void onComplete(Bundle values) {
final String postId = values.getString("post_id");
if (postId != null) {
showToast("Message posted on the wall.");
} else {
showToast("No message posted on the wall.");
}
}
}

How can I change the user while using the Facebook C# sdk on Windows Phone?

I've started using the C# facebook sdk in my WP7 app, and it works, but I can only log in once. I have a class that opens a web browser and loads a facebook login page. I type in my info, and it does what I want it to do. But once I try to log in again, it remembers the info I gave it earlier, and I can't test other facebook accounts. Does anyone know how to clear my old data so I can log in with another account?
You need to perform Logout operation for performing login operation with another account try this code for performing logout.
public partial class LogoutPage : PhoneApplicationPage
{
private Uri navigateUrl;
public FacebookOAuthResult FacebookOAuthResult { get; private set; }
public LogoutPage()
{
var appId = "173963872698818";
string[] extendedPermissions = new[] { "user_about_me", "offline_access" };
var oauth = new FacebookOAuthClient { AppId = appId };
var parameters = new Dictionary<string, object>
{
{ "response_type", "token" },
{ "display", "wap" } //"popup works, touch not works
};
if (extendedPermissions != null && extendedPermissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extendedPermissions));
parameters["scope"] = scope.ToString();
}
var loginUrl = oauth.GetLoginUrl(parameters);
var logoutParameters = new Dictionary<string, object>
{
{ "next", loginUrl }
};
//Redirect to the following url.
// https://www.facebook.com/logout.php?next=YOUR_URL&access_token=ACCESS_TOKEN
//this.navigateUrl = oauth.GetLogoutUrl(logoutParameters);
var a = App.Current as App;
string absoluteURI = " https://www.facebook.com/logout.php?next=http://www.fengshuiexplorer.host56.com&access_token=" + a.myToken;
this.navigateUrl = new Uri(absoluteURI);
InitializeComponent();
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
webBrowser1.Navigate(this.navigateUrl);
}
private void webBrowser1_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
FacebookOAuthResult result;
if (FacebookOAuthResult.TryParse(e.Uri, out result))
{
this.FacebookOAuthResult = result;
var a = App.Current as App;
a.isLoggedIn = false;
NavigationService.GoBack();
}
else
{
this.FacebookOAuthResult = null;
}
}
}
Or you could try to call below code snippets before you log in again.
await new WebBrowser().ClearCookiesAsync();

MVC 2.0 - Custom handling of all errors to return json

I have an MVC 2 app that I want all requests to return json. I have overridden a HandleErrorAttribute and an AuthorizeAttribute. My goal is that all errors (even 403 and 404) are returned as json.
Here is my error handler. ExceptionModel is a simple class defining any error returned by my application. The Exception handler is a class that translates the error details into a formatted e-mail and sends it to me.
public class HandleErrorJsonAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
context.ExceptionHandled = true;
RaiseErrorSignal(context.Exception);
context.RequestContext.HttpContext.Response.ContentType = "application/json";
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(context.HttpContext.Response.Output, new ExceptionModel(context.Exception));
}
private static void RaiseErrorSignal(Exception ex)
{
IExceptionHandler handler = Resolve();
handler.HandleError(ex.GetBaseException());
}
private static IExceptionHandler Resolve()
{
return ServiceLocator.Locate<IExceptionHandler>();
}
}
Here is the Exception model for clarification
public class ExceptionModel
{
public int ErrorCode { get; set; }
public string Message { get; set; }
public ExceptionModel() : this(null)
{
}
public ExceptionModel(Exception exception)
{
ErrorCode = 500;
Message = "An unknown error ocurred";
if (exception != null)
{
if (exception is HttpException)
ErrorCode = ((HttpException)exception).GetHttpCode();
Message = exception.Message;
}
}
public ExceptionModel(int errorCode, string message)
{
ErrorCode = errorCode;
Message = message;
}
}
and finally, my custom authorize attribute. I an using forms auth, but I did not want any of the automatic redirection. I simply want the error to show on the screen and stop any further processing.
public class AuthorizeTokenAttribute : System.Web.Mvc.AuthorizeAttribute
{
public bool SuperAdminOnly { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = base.AuthorizeCore(httpContext);
if(!SuperAdminOnly)
return authorized;
if(!authorized)
return authorized;
return SessionHelper.UserIsSuperAdmin(httpContext.User.Identity.Name);
}
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
throw new HttpException(403, "Access Denied");
}
}
This all works great for most errors, but it is missing one thing. I have a controller action like this.
[AuthorizeToken]
[HttpPost]
public JsonResult MyAction()
{
return new JsonResult();
}
It works fine when you submit via post, but on a get I receive an unhandled 404 error.
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource
you are looking for (or one of its
dependencies) could have been removed,
had its name changed, or is
temporarily unavailable. Please
review the following URL and make sure
that it is spelled correctly.
Requested URL: /MyController/MyAction
Version Information: Microsoft .NET
Framework Version:4.0.30319; ASP.NET
Version:4.0.30319.1
This happens on a GET, which is to be expected as default behavior. However, how can I handle for this condition so that I could instead return json like this
{"ErrorCode":404,"Message":"Page Not Found"}
To handle errors personally I prefer the Application_Error event in Global.asax:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
Response.Clear();
Server.ClearError();
var httpException = exception as HttpException;
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "Index";
routeData.Values["error"] = exception;
IController errorController = new ErrorsController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
and then have an ErrorsController:
public class ErrorsController : Controller
{
public ActionResult Index(Exception exception)
{
var errorCode = 500;
var httpException = exception as HttpException;
if (httpException != null)
{
errorCode = httpException.ErrorCode;
}
return Json(new
{
ErrorCode = errorCode,
Message = exception.Message
}, JsonRequestBehavior.AllowGet);
}
}