Facing an issue while working on ODATA with xml response. Getting internal server error at client side. I debug the code at server side nothing went wrong here, proper response object is generating and returning from server side but "500 internal server" error is generating at client end. Same thing perfectly working fine for when we ask for json response. One more thing I wanted to add here when I hit the url without "$select" proper xml response is generating. Please find below the code for both client and server side.
function ConnectXML()
{
var url = 'https://localhost:321/api/performance?$select=EmployeeID';
$.ajax({
type : "GET",
url : url,
dataType: "xml",
success : function(msg){ alert('Success'); } ,
error : function(msg) { alert('Failed'); }
});
}
public IQueryable<AppraisalsList> GetAppraisals()
{
try
{
string appraisalType = string.Empty;
var allUrlKeyValues = ControllerContext.Request.GetQueryNameValuePairs();
string type = allUrlKeyValues.SingleOrDefault(x => x.Key == "type").Value;
if (!string.IsNullOrEmpty(type) && type.ToLower() != "regular" && type.ToLower() != "ondemand")
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid query params"));
BusinessLogic.Appraisal.Appraisal appraisal = new BusinessLogic.Appraisal.Appraisal(new Settings() { Language = "en-US", UserID = 1, ConnectiongString = "Server=Kazim;Database=BEPMS_BEDemo;Integrated Security=SSPI; MultiSubnetFailover=True;multipleactiveresultsets=True;", AdminConnectiongString = "Server=Kazim;Database=BEPMS_AdminPortal;Integrated Security=SSPI; MultiSubnetFailover=True;multipleactiveresultsets=True;", ApplicationResourcePath = #"D:\Projects\BullseyeEvaluation Performance Management System\BullseyePerformance\Main Project\Source\Binaries", FiscalYearStart = 1, FiscalMonths = 12, DateFormat = "MM/dd/yyyy", NumberFormat = "123,456.78", DecimalPlaces = 2 });
return appraisal.GetAppraisalsList(type).AsQueryable();
}
catch (Exception ex)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.InternalServerError, "Some error occured while processing your request"));
}
}
Related
I have this Action method in ASP.NET MVC 5:
namespace LDAPMVCProject.Controllers
{
public class HomeController : Controller
{
public ActionResult UsersInfo(string username, string password)
{
DomainContext result = new DomainContext();
try
{
// create LDAP connection object
DirectoryEntry myLdapConnection = createDirectoryEntry();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
string ADusername = System.Web.Configuration.WebConfigurationManager.AppSettings["ADUserName"];
string ADpassword = System.Web.Configuration.WebConfigurationManager.AppSettings["ADPassword"];
using (var context = new DirectoryEntry("LDAP://mydomain.com:389/DC=mydomain,DC=com", ADusername, ADpassword))
using (var search = new DirectorySearcher(context))
{
// validate username & password
using (var context2 = new PrincipalContext(ContextType.Domain, "mydomain.com", ADusername, ADpassword))
{
bool isvalid = context2.ValidateCredentials(username, password);
if !(isvalid)
return **** // authentication error
}
// create search object which operates on LDAP connection object
// and set search object to only find the user specified
// DirectorySearcher search = new DirectorySearcher(myLdapConnection);
// search.PropertiesToLoad.Add("telephoneNumber");
search.Filter = "(&(objectClass=user)(sAMAccountName=test.test))";
// create results objects from search object
// user exists, cycle through LDAP fields (cn, telephonenumber etc.)
SearchResult r = search.FindOne();
ResultPropertyCollection fields = r.Properties;
foreach (String ldapField in fields.PropertyNames)
{
if (ldapField.ToLower() == "telephonenumber")
{
foreach (Object myCollection in fields[ldapField])
{
result.Telephone = myCollection.ToString();
}
}
else if (ldapField.ToLower() == "department")
{
foreach (Object myCollection in fields[ldapField])
{
result.Department = myCollection.ToString();
}
}
// }
}
if (result.Telephone == null)
return ***** //Telephone is empty
if (result.Department)
return **** // department is empty
string output = JsonConvert.SerializeObject(result);
return Content(output, "application/json");//success
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return View(result);
}
}
}
The action method acts as an API endpoint for our web application, where the API accepts username & password, and does the following:
Validate the username/password against Active Directory
If valid; check if the telephone number is empty >> if so return an error
If valid; check if department is empty >> if so return an error
If valid and info found; return the department & telephone for the user
Now I am a bit confused on how I need to return the JSON for the first 3 points? Should I always return http 200 with a status message (Status : "success" OR Status: "failed")? or if the username/password validation failed then i should return http 401 without having to return any JSON content?
Can anyone help me with this?
I need to write the action method in a standard way that can be consumed by 3rd party application.
Second question: what do I need to return in case the code raised an exception?
Thanks
This is an API error handling and logging design, and the following type of approach works well, to separate the concerns and keep your main logic clean:
DESIGN ERROR RESPONSES
These should be useful to clients, eg if they need to display an error or do something based on a specific cause. A 4xx error might have this payload, along with an HTTP status:
{
"code": "authentication_failed",
"message": "Invalid credentials were provided"
}
A 500 error is often given a different payload based on what a UI will display in this case, and how you look the error up in logs:
{
"code": "authentication_error",
"message": "A problem was encountered during a backend authentication operation",
"area": "LDAP",
"id": 12745,
"utcTime": "2022-07-24T10:27:33.468Z"
}
DESIGN API LOGS
In the first case the server logs might have fields such as these:
{
"id": "7af62b06-8c04-41b0-c428-de332436d52a",
"utcTime": "2022-07-24T10:27:33.468Z",
"apiName": "MyApi",
"operationName": "getUserInfo",
"hostName": "server101",
"method": "POST",
"path": "/userInfo",
"errorData": {
"statusCode": 401,
"clientError": {
"code": "authentication_failed",
"message": "Invalid credentials were provided",
"context": "The account is locked out"
}
}
}
In the second case the server logs might have fields such as these:
{
"id": "7af62b06-8c04-41b0-c428-de332436d52a",
"utcTime": "2022-07-24T10:27:33.468Z",
"apiName": "MyApi",
"operationName": "getUserInfo",
"hostName": "server101",
"method": "POST",
"path": "/userInfo",
"errorData": {
"statusCode": 500,
"clientError": {
"code": "authentication_error",
"message": "A problem was encountered during a backend authentication operation",
"area": "LDAP",
"id": 12745,
"utcTime": "2022-07-24T10:27:33.468Z"
},
"serviceError": {
"details": "Host not found: error MS78245",
"stack": [
"Error: An unexpected exception occurred in the API",
"at DirectorySearcher: 871 ... "
]
}
}
CODE
Perhaps aim to use code similar to this, to represent your desired error and logging behaviour. The ClientError and ServiceError classes enable the above responses and logs. When errors are thrown this should enable you to add useful contextual info:
public class HomeController : Controller
{
public ActionResult UsersInfo(string username, string password)
{
DomainContext result = new DomainContext();
try
{
DirectoryEntry myLdapConnection = createDirectoryEntry();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
string ADusername = System.Web.Configuration.WebConfigurationManager.AppSettings["ADUserName"];
string ADpassword = System.Web.Configuration.WebConfigurationManager.AppSettings["ADPassword"];
using (var context = new DirectoryEntry("LDAP://mydomain.com:389/DC=mydomain,DC=com", ADusername, ADpassword))
using (var search = new DirectorySearcher(context))
{
using (var context2 = new PrincipalContext(ContextType.Domain, "mydomain.com", ADusername, ADpassword))
{
bool isvalid = context2.ValidateCredentials(username, password);
if !(isvalid)
throw new ClientError(401, "authentication_failed", "Invalid credentials were provided", "optional context goes here");
}
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.Filter = "(&(objectClass=user)(sAMAccountName=test.test))";
SearchResult r = search.FindOne();
ResultPropertyCollection fields = r.Properties;
foreach (String ldapField in fields.PropertyNames)
{
if (ldapField.ToLower() == "telephonenumber")
{
foreach (Object myCollection in fields[ldapField])
{
result.Telephone = myCollection.ToString();
}
}
else if (ldapField.ToLower() == "department")
{
foreach (Object myCollection in fields[ldapField])
{
result.Department = myCollection.ToString();
}
}
}
if (result.Telephone == null)
throw new ClientError(400, "invalid_user_data", "User data is invalid", "Telephone is missing");
if (result.Department)
throw new ClientError(400, "invalid_user_data", "User data is invalid", "Department is missing");
string output = JsonConvert.SerializeObject(result);
return Content(output, "application/json");
}
}
catch (Exception e)
{
throw new ServiceError("authentication_error", "A problem was encountered during a backend authentication operation", "LDAP", e);
}
return View(result);
}
}
MIDDLEWARE
The usual pattern is then to use small middleware classes to deal with processing exceptions, returning error responses and writing error logs:
logging filter
exception filter
The type of logic written here will depend a little on your preferences, but might look similar to this:
public class ErrorFilterAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var logEntry = new ErrorLogEntry();
var jsonResponse = ""
var statusCode = 500;
if (filterContext.Exception is ClientError)
{
var clientError = filterContext.Exception as ClientError;
logEntry.AddClientErrorDetails(clientError);
statusCode = clientError.StatusCode;
jsonResponse = clientError.toResponseFormat();
}
if (filterContext.Exception is ServiceError)
{
var serviceError = filterContext.Exception as ServiceError;
logEntry.AddServiceErrorDetails(serviceError);
statusCode = serviceError.StatusCode;
jsonResponse = serviceError.toResponseFormat();
}
logEntry.Write();
filterContext.Result = new JsonResult(jsonResponse);
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = statusCode;
filterContext.ExceptionHandled = true;
}
}
There are a lot of ways to go about this and ultimately you want to have your endpoint behave in a way that whoever is consuming your endpoint expects.
I stumbled across this as an interesting way to handle nuanced errors in a request to your endpoint. Even though this is used for Graph API, you could use the concept for your needs. https://developers.facebook.com/docs/graph-api/guides/error-handling. The TL;DR is to have a standardized json response like:
{
"error": {
"message": "Message describing the error",
"type": "OAuthException",
"code": 190,
"error_subcode": 460,
"error_user_title": "A title",
"error_user_msg": "A message",
"fbtrace_id": "EJplcsCHuLu"
}
}
The HTTP statuse codes are very flexable and can be confused to tell when to use what.
My advice:
Identify the Http status family (X00)
100s: Informational codes: the server acknowledges the request
initiated by the browser and that it is being processed (100–199).
200s: Success codes: request received, understood, processed and
expected info relayed to browser (200–299).
300s: Redirection codes: a different destination has been substituted
for the requested resource; further action by the browser may be
required (300–399).
400s: Client error codes: website or page not reached; page
unavailable or there was a technical problem with the request
(400–499).
500s: Server error codes
Search for the specific Http status code for your response (2XX) here some exemples for the 200 family:
201: Created. Request fulfilled; new resource created. Typical response
after POST requests.
202: Accepted. Browser request accepted, still in process. May or may not
succeed.
For your example I would return:
403: Forbidden - if the user credentials are wrong.
200: Ok - if everythig works well (all the info returned).
The other option is a little tricky, when the user is authenticate but have no valid data.
you can return:
204: No content - because the user is auth but has no data
500: internal server error - because the server cant return the requested
object
404: Not found - (not my personal chois but it is an option)
It also depends on your client and you preferences.
Happy coddind :)
If there's an unhandled server error 500 in ASP.NET MVC, the server returns a HTML page like this:
Question: is it possible to configure the application so that it returns a JSON with the same information instead of the above HTML?
eg:
{
Title:'Maximum request length exceeded',
Description:'An unhandled eception .....',
...etc
}
you need to catch the error somehwere appropriate [i suggest use custom error filter on the controller for example that inherits from HandleErrorAttribute], and override OnException method, from there you can check if it is Ajax, then do something else, here is a snippet that i wrote before (not clean yet)
and dont forget to set the status code!
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
JsonResultObject result = new JsonResultObject();
result.Success = false;
string message = ("Common.WeAreFixing" + " , #" + errorLog.Id.ToString("00000"));
if (filterContext.HttpContext.Request.IsLocal)
{
message = filterContext.Exception.Message + Environment.NewLine + "st: " +
(filterContext.Exception.StackTrace ?? "");
}
result.AlertMessage = new Alert(message, Alert.Type.Error);
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.Result = new JsonDotNetResult()
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = result
};
filterContext.HttpContext.Items["ErrorNumber"] = errorLog.Id.ToString("00000");
}
Within exceptions there is sensitive information including stack details that should not be leaked to the consumer however as you are showing the error screen i am presuming that this is running in a debug environment and that is not an issue.
Also in a non debug environment the exception details may be stripped out of the response so ideally you should form a custom message of Json format that is based off that exception and then log the original stack details so you can handle the issue at a later date.
Something like the below should get you started:
try
{
// do some work
}
catch (ExplicitException ex)
{
// Log the exception(ex);
var message = "Error Doing Work");
return Json(new { status = "Error", message });
}
}
I'm using the following code in a Xamarin Forms app:
HttpResponseMessage response = null;
try
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(register), Encoding.UTF8, "application/json");
response = await client.InvokeApiAsync("register", content, HttpMethod.Post, null, null);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
var def = new { Message = "" };
var errorMessage = JsonConvert.DeserializeAnonymousType(error, def);
return KloverResult.BuildError(true, errorMessage.Message);
}
}
catch (MobileServiceInvalidOperationException e)
{
if (e.Response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
string error = await e.Response.Content.ReadAsStringAsync();
var def = new { Message = "" };
var errorMessage = JsonConvert.DeserializeAnonymousType(error, def);
return KloverResult.BuildError(true, errorMessage.Message);
}
else
{
return KloverResult.BuildError(false, "Invalid username or password");
}
}
The issue that I'm having is when a MobileServiceInvalidOperationException is thrown as a result of a 500. When I try to read the content of the response (e.Response.Content) it's null. When I call the same API using Restlet I get the following response:
{
"Message": "Name jblogs is already taken."
}
This is what I expect to be in my error variable, however it's null.
My question is, should I be able to read the Content of the Response? If so, do I need to do some more setup on the client/server? The API being called is returning the error form a webapi using:
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Name jblogs is already taken.");
Any help would be appreciated.
A 500 response means that the server crashed. It's likely that there was no content in that case.
If your API is returning status=500, then it is doing the wrong thing. What you should be doing is returning a status in the 400 series - 409 (conflict) seems appropriate to me.
If your API is not returning status=500 deliberately, then the server crashed and you don't get content.
According to your description, I built my Mobile App application with a custom WebApi endpoint to test this issue. Based on my test, I leverage Microsoft.Azure.Mobile.Client 3.1.0 to invoke custom WebApi, I could retrieve the content by Response.Content.ReadAsStringAsync() when the response status is 409 or 500 and so on. Here are my code snippet, you could refer to them:
WebApi
[MobileAppController]
public class ValuesController : ApiController
{
public async Task<HttpResponseMessage> Get()
{
await Task.Delay(TimeSpan.FromSeconds(2));
return Request.CreateErrorResponse(HttpStatusCode.Conflict, "Name jblogs is already taken.");
}
}
Client App
try
{
MobileServiceClient client = new MobileServiceClient("https://bruce-chen-002.azurewebsites.net/");
var response = await client.InvokeApiAsync("/api/values", HttpMethod.Get, null);
}
catch (MobileServiceInvalidOperationException e)
{
if (e.Response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
string error = await e.Response.Content.ReadAsStringAsync();
}
}
Result
i am having problem with my Jqueryajax call that will consume one of my web service method via cross domain. i have been trying all the possible way to accomplish but still no success. please help me with what i am doing wrong. may be i need to configure web server for some security settings? below is my code. please let me know if you have any question regarding with my code.
//Using Ajax Post
//Webservice will return JSON Format
//Doesn't work in both FF and IE when host to live server , work in local
//Error : Access is denined in xxxx.js in IE
//Http 403 Forbidden in FF , FF request header is OPTION
//this approach is the simplest and best way for me to use
var myID = $("myID").val();
$.ajax({
type: "POST",
url: "http://www.mywebsite.com/webservice/Webservice.asmx/getInfo",
data: "{myID:'"+ myID + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
Dostuff(data);
},
error: FailureCallBack
});
My webservice will look like this
using System.Web.Script.Services;
[WebService(Namespace = "http://www.mywebsite.com/webservice/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class Webservice : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public object getInfo(string myID)
{
//Do stuff here
return getJSONDataFromDataSet(_DS);
}
}
//second Approch <br/>
//Using Ajax GET , webservice will return XML Format <br/>
//Doesn't work in both FF and IE when host to live <br/>
//Error : Access is denined in xxxx.js in IE <br/>
//returning XML data in FF but showing nothing in page <br/>
var myID = $("myID").val();
$.ajax({
type: "GET",
url: "http://www.mywebsite.com/webservice/Webservice.asmx/getInfo?myID="myID"&callback=?",
success: function(data) {
Dostuff(data);
},
error: FailureCallBack
});
Webservice
public SerializableDictionary<string, object> getInfo(string myID)
{
//Do stuff here
SerializableDictionary<string, object> obj = getJSONFromDataTable(_DS);
return obj;
}
//third Approch
//Using normal GET , webservice will return XML Format
//same problem with second approch
var myID = $("myID").val();
var xmlhttprequest = createRequestObject();
var url = 'http://www.mywebsite.com/webservice/Webservice.asmx/getInfo?myID='myID'';
xmlhttprequest.open("GET", url, true);
xmlhttprequest.onreadystatechange = getData;
xmlhttprequest.send(null);
function getData()
{
if ((xmlhttprequest.readyState == 4) &&( xmlhttprequest.status == 200))
{
var myXml = xmlhttprequest.responseXML;
Dostuff(myXml);
}
}
function createRequestObject()
{
if (window.XMLHttpRequest)
{
return xmlhttprequest = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
return xmlhttprequest = new ActiveXObject("Microsoft.XMLHTTP");
}
}
Webservice is same with second approach
EDIT:
now i am getting Access is denied , javascript error for both POST and GET request in IE.
in fiddler i can see Firefox returning the Xml data but nothing showing in page, so i put a alert box in getData
function, myXml variable value is always null, strange i only put 1 alert box and it show alert 3 times.
below is my code
var myID = $("myID").val();
var xmlhttprequest = createRequestObject();
var encodeUrl = escape(_utf8_encode("http://www.mywebsite.com/webservice/Webservice.asmx/getInfo?myID="myID));
var url = 'http://www.mywebsite.com/webservice/proxy.aspx?url='+encodeUrl;
xmlhttprequest.open("GET", url, true); //**ACCESS IS DENIED HERE in this line!!!!**
xmlhttprequest.onreadystatechange = getData;
xmlhttprequest.send(null);
function getData()
{
var myXml = xmlhttprequest.responseXML;
alert(myXml); //ALWAYS NULL and show alert 3 times????
DoStuff(myXml);
}
Please help.
best regards
For security reasons, the ajax requests will not work cross domain. There are two solutions to this.
Make the request to the same server, and use a server based proxy mechanism to then make the request to the other domain.
Use "JSONP", which is an alternative cross way of making ajax like requests. jQuery supports this via the dataType: jsonp rather than json, and there is further explanation via their api docs. This blog entry may be useful - http://bloggingabout.net/blogs/adelkhalil/archive/2009/08/14/cross-domain-jsonp-with-jquery-call-step-by-step-guide.aspx
you will need to create proxy on your domain and pass through the request, explain here: http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/
thanks so much for all the reply and help.
i have solved the problem :D
solution is to use JSONP and Javascript dynamic injection to html page.
below is code
HTML
<body>
<script type="text/javascript">
var url = "http://www.mywebsite.com/Javascript/MYJS.js";
var script = document.createElement("script");
script.setAttribute("src",url);
script.setAttribute("type","text/javascript");
document.body.appendChild(script);
</body>
</script>
MYJS.js
var myID = $("#myID").val();
var url = "http://www.mywebsite.com/Webservice.aspx/getInfo?myID="+myID+"";
if (url.indexOf("?") > -1)
url += "&jsonp=" ;
else
url += "?jsonp=" ;
url += "ShowInfoCallback" + "&" ; //Important put ur callback function to capture the JSONP data
url += new Date().getTime().toString(); // prevent caching
var script = document.createElement("script");
script.setAttribute("src",url);
script.setAttribute("type","text/javascript");
document.body.appendChild(script);
function ShowInfoCallback(data)
{
DoWhateverYouWant(data);
}
Webservice.aspx.cs
using System.Web.Script.Serialization;
public partial class Webservice : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(Request.QueryString["myID"]))
this.getInfo();
else
this.getInfoDetails();
}
public void getInfo()
{
string Callback = Request.QueryString["jsonp"];
string encryptedID = Request.QueryString["myID"];
//Dowhateveryouwanthere
object obj = getJSONFromDataTable(myDataSet.Tables[1]);
JavaScriptSerializer oSerializer = new JavaScriptSerializer();
string sJSON = oSerializer.Serialize(obj);
Response.Write(Callback + "( " + sJSON + " );");
Response.End();
}
public void getInfoDetails()
{
//Same as above
//returning 2 tables , Info and InfoDetails
Response.Write(Callback + "( { 'Info' : " + sJSONDetails +",'InfoDetails' : "+ sJSONService + " } );");
Response.End();
}
}
Thanks again
I am using Facebook connect API to grab my friendlist. It redirects me to the login page.
but when I provide credentials it throws an error something like this;
API Error Code: 100
API Error Description: Invalid parameter
Error Message: Requires valid next URL.
Here is the code;
//my actual values are mentioned in the key
_fbService.ApplicationKey = "KEY";
_fbService.Secret = "Key";
_fbService.IsDesktopApplication = false;
string sessionKey = Session["Facebook_session_key"] as String;
string userId = Session["Facebook_userId"] as String;
// When the user uses the Facebook login page, the redirect back here will will have the auth_token in the query params
string authToken = Request.QueryString["auth_token"];
if (!String.IsNullOrEmpty(sessionKey))
{
_fbService.SessionKey = sessionKey;
_fbService.UserId = userId;
}
else if (!String.IsNullOrEmpty(authToken))
{
_fbService.CreateSession(authToken);
Session["Facebook_session_key"] = _fbService.SessionKey;
Session["Facebook_userId"] = _fbService.UserId;
Session["Facebook_session_expires"] = _fbService.SessionExpires;
}
else
{
Response.Redirect(#"http://www.Facebook.com/login.php?api_key=" + _fbService.ApplicationKey + #"&v=1.0");
}
if (!IsPostBack)
{
// Use the FacebookService Component to populate Friends
//MyFriendList.Friends = _fbService.GetFriends();
MyFriendlist.Friends = _fbService.GetFriends();
}
Does anyone knows how to get rid of this?
Thanks in advance.
Instead of redirecting to the url, try using
base.login=true;
//Response.Redirect(#"http://www.Facebook.com/login.php?api_key=" + _fbService.ApplicationKey + #"&v=1.0");
or
Response.Redirect(#"http://www.Facebook.com/login.php?api_key=" + _fbService.ApplicationKey + #"&v=1.0&next=http://apps.facebook.com/yourapplication");