Simple.OData BeforeRequest event not triggered - c#

I'm using the Simple.OData adapter to try to connect to an OData service. The service needs authentication to connect.
I have registered the BeforeRequest event to set the neccesary headers before doing any request.
However, my BeforeRequest is not triggered at all which results in not being able to open the Context, due too missing credentials and my code hangs and waits forever.
See my code below, am I missing something?
public void GetData()
{
var oDataFeed = new ODataFeed(ApiBaseUrl);
oDataFeed.BeforeRequest += BeforeRequest;
oDataFeed.AfterResponse += AfterResponse;
Context = Database.Opener.Open(ApiBaseUrl);
// do some more
}
private void BeforeRequest(HttpRequestMessage httpRequestMessage)
{
// add headers.
}
It did seem to fire or trigger the event once, however, after a rebuild of the project it doesn't work anymore.

There is a know bug in Simple.Data.Client 3x that affects request interception in certain scenarios. The bug is fixed in the forthcoming version 4 of Simple.OData.Client, currently available as pre-release but it's very stable and comes with tons of new features including support for JSON payload and OData protocol V4.

Related

OWIN Store update, insert, or delete statement affected an unexpected number of rows (0) Error

I'm running into a very odd issue where the refresh token "disappears" after a few hours on an Azure App Service which hosts my Wep Api project. I've implemented OAuth for my password flow. Our AccessToken expires after 1 hour and our RefreshToken expires after one week.
For some background. This is happening on an Azure App service where i'm hosting my Web Api and a mobile front end is making calls to it (there are more than one users/mobile devices making a call to this app service).
Here's what a sample initial call looks like using /token call:
My grant_type is password. Normally i get back a refresh_token field along with the access_token, token_type and expires_in.
Works fine for the first few hours after i push to the app service then refresh_token disappears. I am truly stumped by this issue.
Here's my CreateAsync Code:
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var clientid = context.Ticket.Properties.Dictionary["as:client_id"];
if (string.IsNullOrEmpty(clientid))
{
return;
}
string refreshTokenId = await CreateRefreshTokenId(clientid, context);
if (refreshTokenId != null)
{
context.SetToken(refreshTokenId);
}
else
{
throw new Exception("refresh token could not be created");
}
}
private async Task<string> CreateRefreshTokenId(string clientId, AuthenticationTokenCreateContext context)
{
var ticket = context.Ticket;
var refreshTokenId = Guid.NewGuid().ToString("n");
var refreshTokenLifeTime = ConfigurationManager.AppSettings["as:clientRefreshTokenLifeTime"];
var token = new CreateRefreshTokenDTO
{
RefreshTokenId = refreshTokenId,
ClientId = clientId,
Subject = ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
};
ticket.Properties.IssuedUtc = token.IssuedUtc;
ticket.Properties.ExpiresUtc = token.ExpiresUtc;
token.ProtectedTicket = context.SerializeTicket();
var result = await createRefreshTokenManager.ManagerRequest(new CreateRefreshTokenRequest
{
RefreshToken = token
});
return result.IsError ? null : refreshTokenId;
}
I've added the exception in the else statement to see if it will throw and exception and it does in fact throw, which leads me to believe that the refreshTokenId is null. I've also added logging to a log table but for whatever reason, when this error is thrown it should save to the DB table (which i've tested locally and works) but on the App server it is not saving to the table. Very perplexing... UPDATE: PLEASE SEE UPDATE BELOW ON WHY NO LOGS WERE SAVING
Then, what is supposed to happen after this is that now that the front end (mobile, in this case) has the access and refresh tokens, when the access token expires, another call is made to /token but with grant_type = refresh_token:
UPDATE
Eventually I was able to reproduce the issue locally through trial and error and waiting for access token to expire (not entirely sure). But in any case, I was able to produce this error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
This error was the reason i was not able to save any logs to the DB.
Im using Castle Windsor as my IoC and EF6.
My calls are in this order:
1] Attempt to validate the context. In here i make another await call to a LoginUserManager where I basically get and verify user info
// This is used for validating the context
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
2] CreateAsync for creating access and refresh tokens from Context
public async Task CreateAsync(AuthenticationTokenCreateContext context)
Inside CreateAsync I make an await call CreateOrUpdateRefreshTokenManagerwhich either does an Update if entry exists or a Create. And ultimately make a SaveChanges(). This SaveChanges() is what causes the error If I don't call a SaveChanges() no entry is updated or created in that table. This is odd because in other parts of my code i dont call SaveChanges() at all at the end of the web request lifecycle yet an update/create/delete is made. Im assuming that EF/Windsor handles the saving for me.
My thoughts is that because this flow is different from all my other endpoints and that its handling two Async calls that somewhere in between I am disposing the DbContext and that is maybe why im seeing it failing on the second (CreateAsync) call. Not sure, just my thought here.
Anyway, sorry for the long winded post here. I wanted to post as much info as possible and am hoping that this may also help someone else facing this or similar issue.
Thanks!
UPDATE 2
I've noticed that after getting this error on /token call, any other (AllowAnonymous) calls i make work - even those that involve the DB. But the /token call in particular no longer works. My only way around this is to restart the server.
UPDATE 3
I was able to reproduce this issu ONLY on mobile testing (linked to Azure server) but cannot reproduce locally. Steps I used to reproduce:
Log in with one account
Logout
Log in with another account
Logout
Log in with the first account I tried) - This FAILS
Alright ya'll I was able to figure out this issue and i'll do my best to describe what was happening here.
For those of you who have followed a tutorial such as this one or any other similar one, you'll see that you basically have some repository structure set up along with maybe your own context which you inherit the base context, right?
In my case, I was handling the Dispose of the context at the end of the request by overriding the Dispose(bool disposing) method found in the ApiController class. If you're building a WebApi, you'll know what im talking about because any controllers you write inherit this. And if you've got some IoC set up with Lifetimes set to the end of a request, it'll dispose there :)
However, in this case of the /token call I noticed that we were never hitting any controllers...or at least none that utilized ApiController so i couldn't even hit that Dispose method. That meant that the context stayed "active". And in my second, third, fourth, etc calls to /token endpoint, I noticed in the watcher that the context calls were building up (meaning it was saving prior edits to the context i made from previous /token calls - they were never getting disposed! Thus making the context stale).
Unfortunately, the way around this for my situation was to wrap any context calls made within the /token request in a using statement, that way i knew after the using finished up it would dispose properly. And this seemed to work :)
So if you've got a similar project laid out to mine or similar to that tutorial i shared you may run into this issue.

Universal Windows 10 WebView - how to clear/disable cache?

I am having a lot of trouble clearing the WebView cache in my UWP app.
If I edit the content of a JS file linked from my HTML page, I can't get the change into my app unless I re-install the app.
The static WebView.ClearTemporaryWebDataAsync() method doesn't seem to work.
I have also tried adding headers to the request to disable caching:
private void reloadPage()
{
string url = getUrl();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));
request.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
request.Headers.Add("Pragma", "no-cache");
myWebView.NavigateWithHttpRequestMessage(request);
}
I also tried the following, on a punt (I'm not sure if this affects the WebView's caching behaviour), but still no joy:
private void onWebviewLoaded(object sender, RoutedEventArgs e)
{
Windows.Web.Http.Filters.HttpBaseProtocolFilter myFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
myFilter.CacheControl.WriteBehavior = Windows.Web.Http.Filters.HttpCacheWriteBehavior.NoCache;
myFilter.CacheControl.ReadBehavior = Windows.Web.Http.Filters.HttpCacheReadBehavior.Default;
WebView.ClearTemporaryWebDataAsync().AsTask().Wait();
reloadPage();
}
Any help would be very much appreciated!
EDIT (14/12/15):
I have found that adding headers to the request (as in the first code example above) does work, but only if this has been in place for the lifetime of the app, since install. Which makes sense, as it's just saying not to cache this particular request - it could still use an old cached version.
This works as a cludge for now, but it would be much nicer to be able to make use of caching (e.g. for the duration of an app session), then later clear the cache (e.g. on next startup).
EDIT (14/07/16): The above approach doesn't seem to bear out. Caching behaviour seems to be erratic in the webview...
On a clean install of the app, I can see changes to CSS/JS files with absolutely NO code to clear/disable cache. Then at some seemingly arbitrary point, files seem to be cached, and I cannot clear them from the cache.
This finally works for me:
await WebView.ClearTemporaryWebDataAsync();
Windows.Web.Http.Filters.HttpBaseProtocolFilter myFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
var cookieManager = myFilter.CookieManager;
HttpCookieCollection myCookieJar = cookieManager.GetCookies(new Uri("http://www.msftncsi.com/ncsi.txt"));
foreach (HttpCookie cookie in myCookieJar)
{
cookieManager.DeleteCookie(cookie);
}
I don't know if it helps but try to add a timestamp behind the url (url + "?=" + sometimestamphere)
Refreshing the webview seems to do a reload:
mainWebView.Refresh();
It's definitely a hack, but you may be able to insert at that some point in your application lifecycle to force reloading your content. Perhaps after the "mainWebView_NavigationCompleted()" event?
I had a similar problem with css in an UWP app not getting cleared. I ran ProcessMon and found that the UWP app was caching .css and .js files in Windows 10 at: C:\Users\\AppData\Local\Packages\microsoft.windows.authhost.sso.p_8wekyb3d8bbwe\AC\INetCache\Q8IHZDMV. I'm using the Web Authentication Broker so the scenario might be slightly different. If a location similar to this doesn't pan-out, you might want to try to run processmon (part of the SysInternals suite) when you start-up your UWP app to see if you can identify the path the UWP app is using for caching these assets. Once there, deleting these assets and restarting the app did the trick.

Android - Refit throws UnknownHostException unexpectedly

I'm trying to implement Refit using Xamarin and for some reason it throws a UnknownHostException (UHExc) if I was previously not connected to wifi while the app was open. This doesn't happen consistently though.
I have these two calls to Refit's instantiation of my "Refit-interface": PostLoginAsync and GetDataAsync, as shown below (the guide I've been following is here):
public async Task<SomeClass> PostLogin(string user, string password)
{
SomeClass response = null;
var loginTask = apiService.UserInitiated.PostLoginAsync(new RequestBody(user: user, password: password));
response = await FireWebTask(loginTask);
return response;
}
and
private async Task<List<Data>> GetRemoteDataAsync(string args)
{
List<Data> list = null;
var getDataTask = apiService.UserInitiated.GetDataAsync(args);
list = await FireWebTask(getDataTask);
return list;
}
The "Refit-interface" looks somewhat like this:
...
[Post("/relative/url/to/login")]
Task<SomeClass> PostLoginAsync([Body(BodySerializationMethod.Json)] RequestBody requestBody);
[Get("/relative/url/to/data")]
Task<List<Data>> GetDataAsync([Header("SomeHeader")] string args);
...
When I open the app with no connection to the internet and try to send the PostLogin-request, I get an UHExc as expected. If I then turn on the wifi and try again (without closing the app) I get the UHExc again, only this time with almost no delay as the first time (as if the exception was cached??). Restarting the app and trying again without disconnecting the wifi works fine.
If I do the exact same thing with the second request (GetData) I first get an UHExc (obviously) but when reconnecting the wifi it works flawlessly. So it seems to me like the POST-request caches the exception or something and throws it repeatedly without trying to connect at all. How can I solve this (whatever the problem actually is)?
I also had this problem and after some testing discovered that the issue is with the Fusillade library. Now the initial problem is that the fixing changes are not reflected in the NuGet packages so you need to download the latest source from the Github repo and reference the newer dlls.
Looks like the underlying issue is due to the failed requests getting enqueued and played back even though the request resulted in a WebException.
I included the latest code into my project and confirmed that they are working.

SignalR in SL5 stops working after upgrade to 1.0.1

I have a simple Hub that was working with 1.0.0-rc2 between my web app and my SL5 application.
After upgrading to 1.0.1, my .Net Winform clients can still connect to the hub, but my SL5 client can no longer connect.
Upon calling Subscribe, I can see the Negotiate call in Fiddler (which returns 200, with what appears to be valid JSON), followed by the hub Closed event firing. The Error event never fires, and then that's the end of it. There is no attempt to actually connect, at least as far as I can tell in Fiddler.
Any ideas? Here's my SL5 code, it's pretty simple/straight forward.
hub = new HubConnection("http://localhost/ADE");
hub.Closed += new Action(hub_Closed);
hub.Error += new Action<Exception>(hub_Error);
hub.Reconnected += new Action(hub_Reconnected);
hub.Reconnecting += new Action(hub_Reconnecting);
hub.StateChanged += new Action<StateChange>(hub_StateChanged);
hubProxy = hub.CreateHubProxy(hubName);
//Removed my hubProxy.On calls for brevity.
hub.Start().ContinueWith(task =>
// {
//});
Try this sample that is using SignalR1.0.1 and SL5.
To access SL5 client navigate to http://localhost:18628/SignalR.Sample.SilverlightClientTestPage.aspx
On Fiddler, you should get these http requests
http://localhost:18628/signalr/negotiate?noCache=cd92304d-c824-4c91-abdd-e77c8d096b58
http://localhost:18628/signalr/connect?transport=serverSentEvents&connectionToken=rse-NdoiZ1Hi7riN_beL6J-zrkGMPm1A9p8urTZn_1sTuZVeEzVWayykaN-Km_fmqBoV06D1e7h5fPWl4kgggABs3x7wiItdd8zJKE9FSCjZsYEUQOdFrzAg-WmA7rUx0&connectionData=[{"Name":"SampleHub"}]&noCache=0c4c1fa1-9aa9-409b-acf7-165faa0d699a
http://localhost:18628/signalr/send?transport=serverSentEvents&connectionToken=rse-NdoiZ1Hi7riN_beL6J-zrkGMPm1A9p8urTZn_1sTuZVeEzVWayykaN-Km_fmqBoV06D1e7h5fPWl4kgggABs3x7wiItdd8zJKE9FSCjZsYEUQOdFrzAg-WmA7rUx0

How can I access the contents of an Event fired when running in the TFS Server Context?

I've created a custom event handler for TFS 2012 that fires an event every time a "Work Item" changes. I've followed various examples and found the following code to work on TFS 2012:
public class WorkItemChangedEventHandler : ISubscriber
{
public Type[] SubscribedTypes()
{
return new[] { typeof(WorkItemChangedEvent) };
}
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs,
out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = String.Empty;
try
{
if( notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent )
{
var ev = notificationEventArgs as WorkItemChangedEvent;
EventLog.WriteEntry("WorkItemChangedEventHandler", "WorkItem " + ev.WorkItemTitle + " was modified");
}
}
catch( Exception exception )
{
//must eat all exceptions or TFS will not load the plugin
}
return EventNotificationStatus.ActionPermitted;
}
public string Name
{
get { return "WorkItemChangedEventHandler"; }
}
public SubscriberPriority Priority
{
get { return SubscriberPriority.Normal; }
}
}
SO, while this code runs fine when installed as a .dll in the /plugins directory in TFS, I still don't get how I can get the results from the Event from within external code.
I guess there is some kind of Subscription available through the TFS Server API that lets me subscribe to the events running under the TFS context using a custom event handler (subscriber), but I've tried for a week without luck, so now I'm begging for mercy from the SO community.
What I have is a service that that connects to our Help Desk API and reads Bug Tickets, then I convert this into a serialized local List structure to read from later when I want to check if anything has changed. I then use the TFS API to update the corresponding Work Items, so that everything is in sync.
Everything works on this part of the application, but the problem is that I also need the changes made on TFS (by us developers) to be reflected to the Help Desk Bug tracker.
So I thought that using a WorkItemChanged() event to do this would spare me the manual coding like I did on the other side.
I need to know what fields on the Work Item changed to update the BugTracker with the new value.
Does anybody have a clue as of how to achieve this?
The question really boils down to:
How do I subscribe to the events fired by the above written code from a console or service application?
Help is appreciated.
Chris
You sound like you are not looking for Server side events but rather looking for SOAP events where TFS will call a URL and send a SOAP envelope with the data that you want.
You can just create a web service and get TFS to call it whenever an event of a particular type occurs:
Handling Team Foundation Server Events
However if you are unable to connect from the TFS server to your console application (usually happens with the local app running on your computer rather than on a server) you can create your own message queue that uses a Duplex service.
To do that you would "host" your own web service end point within the event handler code above and have your clients connect to that. I can see many issues with this that you might run into, but if you don't want to poll and you cant get TFS to fire a soap even on your local box then you would have little choice.

Categories