FacebookRealtimeUpdateController Override Post and return 'OK' - asp.net-mvc

Using Mvc.Facebook.Realtime the FacebookRealtimeUpdateController provides a process for handling user events (HandleUpdateAsync) , but not for page events.
Microsoft.AspNet.Mvc.Facebook.Realtime Namespace
I have managed to process page events by overriding the 'POST'
Public Overrides Function Post() As Task(Of Net.Http.HttpResponseMessage)
Dim content = Request.Content
Dim jsonContent As String = content.ReadAsStringAsync().Result
Dim ConvertedJson As RealTimeEvent = JsonConvert.DeserializeObject(Of RealTimeEvent)(jsonContent)
' Do something with the page events
Return MyBase.Post
End Function
However Facebook resends all events immediately , which I believe is because I am not returning a '200 OK' back to Facebook. (See quote)
First you'll need to prepare the page that will act as your callback URL. This URL will need to be accessible by Facebook servers, and be able to receive both the POST data that is sent when an update happens, but also accept GET requests in order to verify subscriptions.
This URL should always return a 200 OK HTTP response when invoked by Facebook.
I wiresharked my server and I do not see a 200 OK HTTP response, so I believe this something to do with the way I am overloading the post.
Can I somehow return an OK response from my overridden function or maybe it would be better to drop the whole Microsoft.AspNet.Mvc.Facebook.Realtime solution and just handle the Subscription GETs and Posts from facebook myself?
Update: I turned off "only my own code' and I can see an exception occurring in the AspNet.MVC.Facebook.dll.
So new question, How do I isolate this exception?

For others looking.
The issue was actually the HandleUpdateAsync function which must be overridden. This is fired after the 'Post'
If you don't return a valid task the exception is thrown inside AspNet.MVC.Facebook.dll and Facebook is never given a 200 OK.
I was using This blog on how to use the FacebookRealtimeUpdateController but in that version the 'HandleUpdateAsync' does not return a task and the processing is done in the function.
So by creating a task that does nothing , everything appears to be working fine.
Public Overrides Function HandleUpdateAsync(notification As ChangeNotification) As Task
Dim newtask As New Task(New System.Action(Sub()
Dim x As String = ""
End Sub))
Return newtask
End Function
Edit: But it creates a massive memory leak which cannot be cleared even with recycling..
So the real solution is to just create your own controller and forget the FacebookRealtimeUpdateController completely.
Very easy to do and saves allot of hassle!

Related

Wait Until OData Request Completed

I have a requirement to oData service inside onExit hook method. I have written below code but unfortunately oData service is not getting called as view is destroyed immediately . Is there any way to add wait or delay the destroy of view until oData read request is complete ?
window.addEventListener("beforeunload", (event) => {
this.fnUnlockGremienVersion();
var s;
event = event || window.event;
if (this._PreviousGreVersion) {
s = "Your most recent changes are still being saved. " +
"If you close the window now, they may not be saved.";
event.returnValue = s;
return s;
}
});
UI5 has no support for such a workflow and it's not only "UI5", in fact webpages can't block/trap a user within a page for various reasons. Just remember the annoying un-closable webpages from the 2000s. Browser dropped support for such things; except a very simple pop-up api which is supported by UI5.
i assume you are in the shell.
Use the dirty flag properly(set it as long there are unsaved changes or a request still running) and the user will get a popup.
https://sapui5.hana.ondemand.com/sdk/#/api/sap.ushell.services.Container%23methods/setDirtyFlag

API call not working from Azure

I have an test API (get method) which I have deployed on production with test data.
This API if I call from anywhere directly from Browser , it works perfectly.
I created a web application, just a submit click button, to call that API. I deployed web application on Azure.
It doesn't work. It keeps giving me Operation has timed out exception. API doesn't get a hit. API get request works from browser. I tried to using logger in api, log file remains blank.
Can please anyone help me in this?
EDIT:
When I call through browser, I get following response
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ArrayOfMessage xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ValidationWebApi">
<Message>
<MessageDesc>
[{"NO":"111","NAME":"Miss Jane ","EXTENSION":"","MOBILE":"","EMAIL_ID":SOME EMAIL ID}]
</MessageDesc>
<MessageId i:nil="true"/>
<WebApiInfo i:nil="true"/>
<isValid>1</isValid>
</Message>
</ArrayOfMessage>
But if I call through Azure hosted site, I get following error...
`System.Net.WebException: The operation has timed out at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request) at System.Net.WebClient.DownloadString(Uri address) at System.Net.WebClient.DownloadString(String address) at Test.btnSubmit_Click(Object sender, EventArgs e)
Edit:
The way this has been called to check whether it gets hit or not is as follows
This is button click event. we are just trying to print this response on screen. Get method is used.
string strApi = "https://domain.com/myApiName/Jane";
try
{
using (var client = new WebClient())
{
var result = client.DownloadString(strApi);
Response.Write(result);
}
}
I get exception on var result statement. It waits there for sometime and gives exception.
Regards,
Ashay
Try enabling CORS ( cross-origin HTTP request ) to you API controller ..
Thanks
Kasam Shaikh

ios swift 2.1 - unable to send Patch request with body

I'm trying to write a http rest client for my webservice and i need to send some PATCH requestes with data in the body.
I'm using the JUST library for sending requests ( https://github.com/JustHTTP/Just )
My express application just doesn't see the request.
Here's some code (i'm testing in playground, and everything went fine with other kind of requests like put, post...)
headers = ["accept":"application/json","content-type":"application/json","authorization":"key"] //key is ok
var data = ["id":3, "quantity":6]
var r = Just.patch("http://api.marketcloud.it/v0/carts/1233", headers:headers, data:data) //1233 is a cart Id
print(r)
print(r.json)
The method Just.patch returns an HTTPResult Object.
this says 'OPTIONS http://api.marketcloud.it/v0/carts/13234 200'
Also this object should contain a json, but it's 'nil'.
On the server-side, my express applications doesn't receive the request (it just logs an 'OPTION', but nothing else).
Could this be a playground-related problem? Or a just-related one?
Thanks for any suggestion
I managed to contact the library's author via twitter and he fixed the bug and answered me in less than 24h!
Here's the new release of the library.
https://github.com/JustHTTP/Just/releases

HTTPClient GetAsync post object

We currently have a generic MVC method that GET's data from ASP.NET Web API
public static T Get<T>(string apiURI, object p)
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Config.API_BaseSite);
HttpResponseMessage response = client.GetAsync(apiURI).Result;
// Check that response was successful or throw exception
if (response.IsSuccessStatusCode == false)
{
string responseBody = response.Content.ReadAsStringAsync().Result;
throw new HttpException((int)response.StatusCode, responseBody);
}
T res = response.Content.ReadAsAsync<T>().Result;
return (T)res;
}
}
Our question is:- obviously, we can not send 'p' as you would with a post,
client.PostAsync(apiURI, new StringContent(p.ToString(), Encoding.UTF8, "application/json")
but how we go about sending this object / JSON with a get.
We have seen sending it as part of the URL, however, is there an alternative?
GET sends the values with the query string (end of url), in regards to "but how we go about sending this object / JSON with a get. We have seen sending it as part of the URL, however, is there an alternative?".
The alternative is POST or PUT.
PUT is best used when the user creates the key/url. You can look at examples such as cnn.com - where the URL's are just short versions of the article title. You want to PUT a page at that URL.
Example:
http://newday.blogs.cnn.com/2014/03/19/five-things-to-know-for-your-new-day-wednesday-march-19-2014/?hpt=hp_t2
has the url of "five-things-to-know-for-your-new-day-wednesday-march-19-2014", which was generated from the article title of "Five Things to Know for Your New Day – Wednesday, March 19, 2014"
In general, you should follow these guidelines:
Use GET when you want to fetch data from the server. Think of search engines. You can see your search query in the query string. You can also book mark it. It doesn't change anything on the server at all.
Use POST when you want to create a resource.
Use PUT when you want to create resources, but it also overwrites them. If you PUT an object twice, the servers state is only changed once. The opposite is true for POST
Use DELETE when you want to delete stuff
Neither POST nor PUT use the query string. GET does

CI 2.0.3 session heisenbug: session is lost after some time 20 minutes, only on server redirect, nothing suspicious in the logs

I can't seem to make any progress with this one. My CI session settings are these:
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = FALSE;
$config['sess_time_to_update'] = 7200;
$config['cookie_prefix'] = "";
$config['cookie_domain'] = "";
$config['cookie_path'] = "/";
$config['cookie_secure'] = FALSE;
The session library is loaded on autoload. I've commented the sess_update function to prevent an AJAX bug that I've found about reading the CI forum.
The ci_sessions table in the database has collation utf8_general_ci (there was a bug that lost the session after every redirect() call and it was linked to the fact that the collation was latin1_swedish_ci by default).
It always breaks after a user of my admin section tries to add a long article and clicks the save button. The save action looks like this:
function save($id = 0){
if($this->my_model->save_article($id)){
$this->session->set_flashdata('message', 'success!');
redirect('admin/article_listing');
}else{
$this->session->set_flashdata('message', 'errors encountered');
redirect('admin/article_add');
}
}
If you spend more than 20minutes and click save, the article will be added but on redirect the user will be logged out.
I've also enabled logging and sometimes when the error occurs i get the message The session cookie data did not match what was expected. This could be a possible hacking attempt. but only half of the time. The other half I get nothing: a message that I've placed at the end of the Session constructor is displayed and nothing else. In all the cases if I look at the cookie stored in my browser, after the error the cookie's first part doesn't match the hash.
Also, although I know Codeigniter doesn't use native sessions, I've set session.gc_maxlifetime to 86400.
Another thing to mention is that I'm unable to reproduce the error on my computer but on all the other computers I've tested this bug appears by the same pattern as mentioned above.
If you have any ideas on what to do next, I'd greatly appreciate them. Changing to a new version or using a native session class (the old one was for CI 1.7, will it still work?) are also options I'm willing to consider.
Edit : I've run a diff between the Session class in CI 2.0.3 and the latest CI Session class and they're the same.
Here's how I solved it: the standards say that a browser shouldn't allow redirects after a POST request. CI's redirect() method is sending a 302 redirect by default. The logical way would be to send a 307 redirect, which solved my problem but has the caveat of showing a confirm dialog about the redirect. Other options are a 301 (meaning moved permanently) redirect or, the solution I've chosen, a javascript redirect.

Resources