CrossGeolocator's GetPositionAsync does not work - c#

I am using CrossGeolocator to retrieve the current latitude and longitude of the device. However I am using it inside an OnAppearing override method and it is not working. The GetPositionAsync method hangs the App.
protected override void OnAppearing()
{
base.OnAppearing();
var position = GetPosition().Result;
var lat = position.Latitude;
var lon = position.Longitude;
}
private static async Task<Position> GetPosition()
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
var position = await locator.GetPositionAsync(10000);
return position;
}
Detail is that I am using this same GetPosition method in buttons in the application and works perfectly.
Could someone help me in this matter?

Try this:
Create a global variable:
private Position _position;
Then call ur method to get the position on constructor.
Re-write ur method like this:
public async void GetPosition()
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
var myPosition = await locator.GetPositionAsync();
_position = new Position(myPosition.Latitude, myPosition.Longitude);
}
Then make a while where u want to use this:
while(_position == new Postion(0,0))
GetPosition();

This worked for me.
Set up the xamarin forms maps as stated in the link.
https://developer.xamarin.com/guides/xamarin-forms/user-interface/map/
set permissions as stated in below link
https://jamesmontemagno.github.io/GeolocatorPlugin/GettingStarted.html
you may make use of https://jamesmontemagno.github.io/GeolocatorPlugin/CurrentLocation.html
using Plugin.Geolocator;
using System;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Xaml;
namespace MapApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MapPage : ContentPage
{
private Position _position;
public MapPage()
{
InitializeComponent();
var map = new Map(
MapSpan.FromCenterAndRadius(
new Position(37, -122), Distance.FromMiles(0.3)))
{
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
if (IsLocationAvailable())
{
GetPosition();
map.MoveToRegion(MapSpan.FromCenterAndRadius(_position, Distance.FromMiles(1)));
}
map.MapType = MapType.Street;
var stack = new StackLayout { Spacing = 0 };
stack.Children.Add(map);
Content = stack;
}
public bool IsLocationAvailable()
{
if (!CrossGeolocator.IsSupported)
return false;
return CrossGeolocator.Current.IsGeolocationAvailable;
}
public async void GetPosition()
{
Plugin.Geolocator.Abstractions.Position position = null;
try
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 100;
position = await locator.GetLastKnownLocationAsync();
if (position != null)
{
_position = new Position(position.Latitude, position.Longitude);
//got a cahched position, so let's use it.
return;
}
if (!locator.IsGeolocationAvailable || !locator.IsGeolocationEnabled)
{
//not available or enabled
return;
}
position = await locator.GetPositionAsync(TimeSpan.FromSeconds(20), null, true);
}
catch (Exception ex)
{
throw ex;
//Display error as we have timed out or can't get location.
}
_position = new Position(position.Latitude, position.Longitude);
if (position == null)
return;
}
}
}

Things to take care is
calling the method in constructor.
have available lat long if exists.
VERY IMP have try catch, without try catch the application crashes. Not writing any thing in catch as don;t want to catch exception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Foundation;
using UIKit;
using System.Threading.Tasks;
using Plugin.Geolocator.Abstractions;
using Plugin.Geolocator;
using System.Diagnostics;
using Xamarin.Forms;
using abcde.iOS;
[assembly: Xamarin.Forms.Dependency(typeof(GPSLocation_iOS))]
namespace abcde.iOS
{
public class GPSLocation_iOS : IGPSLocation
{
public Position _position;
public GPSLocation_iOS()
{
GetPosition();
}
public Dictionary<string, string> GetGPSLocation()
{
Dictionary<string, string> dictPosition = new Dictionary<string, string>();
dictPosition.Add("latitude", _position.Latitude.ToString());
dictPosition.Add("longitude", _position.Longitude.ToString());
return dictPosition;
}
public async void GetPosition()
{
try
{
var locator = CrossGeolocator.Current;
_position = await locator.GetLastKnownLocationAsync();
if (_position == null)
{
locator.DesiredAccuracy = 50;
var myPosition = await locator.GetPositionAsync();
_position = new Position(myPosition.Latitude, myPosition.Longitude);
}
}
catch (Exception ex)
{
}
}

latest 2018-07-10 version update,
To support iOS 11 and earlier, you can include all three keys:
NSLocationWhenInUseUsageDescription,
NSLocationAlwaysAndWhenInUseUsageDescription
NSLocationAlwaysUsageDescription.
I use Xamarin to write app, and it works fine in my iOS project
reference : https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/map

I solved my problem just adding the parameters in GetPositionAsync: null and true.
var location = await locator.GetPositionAsync(TimeSpan.FromSeconds(20), null, true);
and turn on the GPS
My problem was on Android 4.4

Related

Issue with Xamarin.Google.Guava

I think I understand the error but I have no idea how to solve it :/
This is the error I'm getting:
"JAR library references with identical file names but different contents were found: __reference__guava.jar. Please remove any conflicting libraries from EmbeddedJar, InputJar and AndroidJavaLibrary. Food_Recipe_App.Android"
Reason to why I want Xamarin.Google.Guava is that someone said that it would fix an issue I had earlier;
"System.NullReferenceException
Message=Object reference not set to an instance of an object."
Which, honestly, I have no idea how to solve either.
I'm thankful for all help :)
Edit: It breaks after calling the Firestore.Read();
protected override async void OnAppearing()
{
base.OnAppearing();
//using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation))
//{
// conn.CreateTable<Recipe>();
// var recipes = conn.Table<Recipe>().ToList();
// //recipeListView.ItemsSource = recipes;
//};
var recipes = await Firestore.Read(); ***//this line breaks***
//assignRecipesToDays(recipes);
}
This is the Read method from my Firestore script:
public async Task<List<Recipe>> Read()
{
try
{
hasReadRecipes = false;
var collection = FirebaseFirestore.Instance.Collection("recipes");
var query = collection.WhereEqualTo("userId", FirebaseAuth.Instance.CurrentUser.Uid);
query.Get().AddOnCompleteListener(this);
for (int i = 0; i < 50; i++)
{
await System.Threading.Tasks.Task.Delay(100);
if (hasReadRecipes)
break;
}
return recipes;
}
catch (Exception ex)
{
return recipes;
}
}
And this is the whole Firestore Script if that helps solving it:
using Android.App;
using Android.Content;
using Android.Gms.Tasks;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Firebase.Auth;
using Firebase.Firestore;
using Food_Recipe_App.Assets.Classes;
using Food_Recipe_App.Helpers;
using Java.Interop;
using Java.Util;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xamarin.Forms;
[assembly: Dependency(typeof(Food_Recipe_App.Droid.Dependencies.Auth))]
namespace Food_Recipe_App.Droid.Dependencies
{
public class Firestore : Java.Lang.Object, IFirestore, IOnCompleteListener
{
List<Recipe> recipes;
bool hasReadRecipes = false;
public Firestore()
{
recipes = new List<Recipe>();
}
public async Task<bool> Delete(Recipe recipe)
{
try
{
var collection = FirebaseFirestore.Instance.Collection("recipes");
collection.Document(recipe.Id).Delete();
return true;
}
catch (Exception ex)
{
return false;
}
}
public async Task<bool> Insert(Recipe recipe)
{
try
{
var recipeDocument = new Dictionary<string, Java.Lang.Object>()
{
{ "title", recipe.title },
{ "description", recipe.description },
{ "creatorUserId", FirebaseAuth.Instance.CurrentUser.Uid }
};
var collection = Firebase.Firestore.FirebaseFirestore.Instance.Collection("recipes");
collection.Add(new HashMap(recipeDocument));
return true;
}
catch (Exception ex)
{
return false;
}
}
public void OnComplete(Android.Gms.Tasks.Task task)
{
if (task.IsSuccessful)
{
var documents = (QuerySnapshot)task.Result;
recipes.Clear();
foreach (var doc in documents.Documents)
{
Recipe newRecipe = new Recipe()
{
title = doc.Get("title").ToString(),
description = doc.Get("description").ToString(),
Id = doc.Id
};
recipes.Add(newRecipe);
}
}
else
{
recipes.Clear();
}
hasReadRecipes = true;
}
public async Task<List<Recipe>> Read()
{
try
{
hasReadRecipes = false;
var collection = FirebaseFirestore.Instance.Collection("recipes");
var query = collection.WhereEqualTo("userId", FirebaseAuth.Instance.CurrentUser.Uid);
query.Get().AddOnCompleteListener(this);
for (int i = 0; i < 50; i++)
{
await System.Threading.Tasks.Task.Delay(100);
if (hasReadRecipes)
break;
}
return recipes;
}
catch (Exception ex)
{
return recipes;
}
}
public async Task<bool> Update(Recipe recipe)
{
try
{
var recipeDocument = new Dictionary<string, Java.Lang.Object>()
{
{ "title", recipe.title },
{ "description", recipe.description },
{ "creatorUserId", FirebaseAuth.Instance.CurrentUser.Uid }
};
var collection = FirebaseFirestore.Instance.Collection("recipes");
collection.Document(recipe.Id).Update(recipeDocument);
return true;
}
catch (Exception ex)
{
return false;
}
}
}
}

Wait for notification async call

I am trying to get the lync presence status of a given user. My code will talk to lync server 2010 using UCMA 4.0 in 64 bit env.
here is my code to wait for an async call to get the lync status.
private async void getNotifications(UserEndpoint endpoint, string useridSIP)
{
_userEndpoint.PresenceServices.BeginPresenceQuery(
new[] { useridSIP },
new[] { "state" },
null,
(ar) => {
Task<List<RemotePresentityNotification>> notificationFetch = _userEndpoint.PresenceServices.EndPresenceQuery(ar).ToList<RemotePresentityNotification>();
List<RemotePresentityNotification> result = await notificationFetch;
result.ForEach(x => {
LyncUser user = new LyncUser();
if (x.AggregatedPresenceState != null)
{
user.Presence = x.AggregatedPresenceState.Availability.ToString();
}
else
{
user.Presence = "Unknown";
}
user.UserName = x.PresentityUri.ToString();
usersWithStatus.Add(user);
});
},
null);
}
I am not sure how to wait till the List<RemotePresentityNotification> results are returned
Task<List<RemotePresentityNotification>> notificationFetch = _userEndpoint.PresenceServices.EndPresenceQuery(ar).ToList<RemotePresentityNotification>();
List<RemotePresentityNotification> result = await notificationFetch;
The entire source code.
using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Collaboration.Presence;
using Oobe.Bobs.Lync.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
namespace xxxx.xxxx.xxxx
{
public class OneTimePresence
{
private UCMASampleHelper _helper;
private UserEndpoint _userEndpoint;
public List<LyncUser> usersWithStatus = new List<LyncUser>();
public LyncPresenceChecker _checker { get; set; }
public OneTimePresence(string useridSIP, LyncPresenceChecker checker)
{
_checker = checker;
_helper = new UCMASampleHelper();
string endpoint = String.Format("OneTime Presence query for {0}", useridSIP);
_userEndpoint = _helper.CreateEstablishedUserEndpoint(endpoint);
getNotifications(_userEndpoint, useridSIP);
_helper.ShutdownPlatform();
}
protected void EndgetNotification(object sender, RemotePresentitiesNotificationEventArgs e)
{
e.Notifications.ToList<RemotePresentityNotification>().ForEach(x =>
{
LyncUser user = new LyncUser();
if (x.AggregatedPresenceState != null)
{
user.Presence = x.AggregatedPresenceState.Availability.ToString();
}
else
{
user.Presence = "Unknown";
}
user.UserName = x.PresentityUri.ToString();
usersWithStatus.Add(user);
});
_checker.Clients.All.updateLyncUserPresence(usersWithStatus);
}
private void getNotifications(UserEndpoint endpoint, string useridSIP)
{
_userEndpoint.PresenceServices.BeginPresenceQuery(
new[] { useridSIP },
new[] { "state" },
EndgetNotification,
(ar) => {
ar.AsyncWaitHandle.WaitOne();
List<RemotePresentityNotification> result = _userEndpoint.PresenceServices.EndPresenceQuery(ar).ToList<RemotePresentityNotification>();
result.ForEach(x =>
{
LyncUser user = new LyncUser();
if (x.AggregatedPresenceState != null)
{
user.Presence = x.AggregatedPresenceState.Availability.ToString();
}
else
{
user.Presence = "Unknown";
}
user.UserName = x.PresentityUri.ToString();
usersWithStatus.Add(user);
});
},
null);
if (usersWithStatus.Count > 0)
{
_checker.Clients.All.updateLyncUserPresence(usersWithStatus);
}
}
}
}
I believe that you are looking for the Task.Factory.FromAsync method. This method is a wrapper around the Begin and End async pattern -- detailed here. For example you'd want to do this instead:
private async Task<List<RemotePresentityNotification>> GetNotifications(UserEndpoint endpoint, string useridSIP)
{
var task = Task.Factory.FromAsync(
_userEndpoint.PresenceServices.BeginPresenceQuery,
_userEndpoint.PresenceServices.EndPresenceQuery,
new[] { useridSIP },
new[] { "state" });
var results = await task;
return results.ToList();
}
Avoid async void detailed here
Use async only if there is a corresponding await
With this in place you could then await it and handle it as you see fit, like so:
private async Task SomeCaller(UserEndpoint endpoint, string useridSIP)
{
var list = await GetNotifications(endpoint, useridSIP);
// ... do stuff with it
}
Update 1
Consider ensuring that the PresenceServices are in fact available by checking the State as detailed here.
As long as the endpoint’s State property is set to Established, all presence services are available to it.
Additionally, this might be helpful to look at.

Removing and Adding content with Code Fix Provider

I had that previous question which was intended to resolved the state of a local variable / parameter. It works fine, I tweak it a little bit and it looks like this now :
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class LocalVariableNotUsedAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor descriptor = new DiagnosticDescriptor(
CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID,
GettextCatalog.GetString("Local variable is never used"),
GettextCatalog.GetString("Local variable is never used"),
DiagnosticAnalyzerCategories.RedundanciesInDeclarations,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
helpLinkUri: HelpLink.CreateFor(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID)
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
(nodeContext) =>
{
Diagnostic diagnostic;
if (TryGetDiagnostic(nodeContext, out diagnostic))
{
nodeContext.ReportDiagnostic(diagnostic);
}
},
SyntaxKind.LocalDeclarationStatement
);
}
private static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic)
{
diagnostic = default(Diagnostic);
if (nodeContext.IsFromGeneratedCode())
return false;
var localDeclarationUnused = nodeContext.Node as LocalDeclarationStatementSyntax;
var body = localDeclarationUnused?.Parent as BlockSyntax;
if (body == null)
return false;
var dataFlow = nodeContext.SemanticModel.AnalyzeDataFlow(body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead).ToArray();
if (unused == null)
return false;
if (localDeclarationUnused.Declaration == null || !localDeclarationUnused.Declaration.Variables.Any())
return false;
var localDeclarationSymbol = nodeContext.SemanticModel.GetDeclaredSymbol(localDeclarationUnused.Declaration.Variables.FirstOrDefault());
if (unused.Any())
{
if (unused.Contains(localDeclarationSymbol))
{
diagnostic = Diagnostic.Create(descriptor, localDeclarationUnused.Declaration.GetLocation());
return true;
}
}
return false;
}
}
}
I have build a code fix provider which is working around 40% of the time, when checking the success rate of the NUnit test. Even though I know the code is OK, there seem to be some error on my machine that only arrives when the code fix is being run. I know this because I can debug the analyzer for the tests and each one are fine.
When the code fix provider is being run, I have this error that I can't shake for some reason : "System.ArgumentNullException : Value cannot be null.
Parameter name : declaration"
I have tried debugging the code fix provider, but nothing showed me where that declaration parameter could be located.
Moreover, I am used with code fix providers that need to either replace and remove nodes. But I'm not used to fix an error and add content and I'm wondering how to do such a thing.
Here's my code fix provider which does not take care of adding information at the moment :
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeFixes;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[ExportCodeFixProvider(LanguageNames.CSharp), System.Composition.Shared]
public class LocalVariableNotUsedCodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds
{
get
{
return ImmutableArray.Create(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID);
}
}
public override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public async override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
var span = context.Span;
var diagnostics = context.Diagnostics;
var root = await document.GetSyntaxRootAsync(cancellationToken);
var diagnostic = diagnostics.First();
var node = root.FindNode(context.Span);
if (node == null)
return;
var newRoot = root.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia);
context.RegisterCodeFix(CodeActionFactory.Create(node.Span, diagnostic.Severity, "Remove unused local variable", document.WithSyntaxRoot(newRoot)), diagnostic);
}
}
}
and here are the tests that I'm using to make sure that the fix is ok. The last two are running just fine :-)
using NUnit.Framework;
using RefactoringEssentials.CSharp.Diagnostics;
namespace RefactoringEssentials.Tests.CSharp.Diagnostics
{
[TestFixture]
public class LocalVariableNotUsedTests : CSharpDiagnosticTestBase
{
[Test]
public void TestUnusedVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
$int i$;
}
}";
var output = #"
class TestClass {
void TestMethod ()
{
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input, output);
}
[Test]
public void TestUnusedVariable2()
{
var input2 = #"
class TestClass {
void TestMethod ()
{
$int i, j$;
j = 1;
}
}";
var output2 = #"
class TestClass {
void TestMethod ()
{
int j;
j = 1;
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input2, output2);
}
[Test]
public void TestUsedVariable()
{
var input1 = #"
class TestClass {
void TestMethod ()
{
$int i = 0$;
}
}";
var input2 = #"
class TestClass {
void TestMethod ()
{
int i;
i = 0;
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input1);
Analyze<LocalVariableNotUsedAnalyzer>(input2);
}
[Test]
public void TestUnusedForeachVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
var array = new int[10];
foreach (var i in array) {
}
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input);
}
[Test]
public void TestUsedForeachVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
var array = new int[10];
int j = 0;
foreach (var i in array) {
j += i;
}
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input);
}
}
}
Is there is anything that is not clear, I will make sure to update my thread appropriately.

Lock analog in Azure

I need to implement some thread consequent logic in Azure web instances.
I have some code like this:
lock (_bookingLock)
{
// Check for a free time
bool isTimeFree = _scheduleService.IsTimeFree(dateTimeGuidId);
//* race condition here
if (isTimeFree)
{
// Make a booking. So this time is busy
newBookingId = _paymentService.CreateBooking(dateTimeGuidId).ToString();
}
}
But I can't use lock in a multi instance environment and I can't omit lock because there is a race condition at *. What is the best approach here?
I decided to use blob leases. I upgraded smarx's code to use Azure Storage client version 2 or 3 and wrote one addtitional method. Here is full code:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage.Shared.Protocol;
using Microsoft.WindowsAzure.Storage.Blob.Protocol;
using System.Configuration;
namespace TerminalManager.Domain.Foundation.BlobLeases
{
public class AutoRenewLease : IDisposable
{
public bool HasLease { get { return leaseId != null; } }
AccessCondition _accessCondition;
private CloudBlockBlob blob;
private string leaseId;
private Thread renewalThread;
private bool disposed = false;
public static void DoOnce(CloudBlockBlob blob, Action action) { DoOnce(blob, action, TimeSpan.FromSeconds(5)); }
public static void DoOnce(CloudBlockBlob blob, Action action, TimeSpan pollingFrequency)
{
// blob.Exists has the side effect of calling blob.FetchAttributes, which populates the metadata collection
while (!blob.Exists() || blob.Metadata["progress"] != "done")
{
using (var arl = new AutoRenewLease(blob))
{
if (arl.HasLease)
{
action();
blob.Metadata["progress"] = "done";
AccessCondition ac = new AccessCondition();
ac.LeaseId = arl.leaseId;
blob.SetMetadata(ac);
}
else
{
Thread.Sleep(pollingFrequency);
}
}
}
}
/// <summary>
/// Выполнить последовательно
/// </summary>
/// <param name="lockBlobName">имя блоба - просто буквы</param>
/// <param name="action"></param>
/// <param name="cnStrName">из конфига</param>
/// <param name="containerName">из конфига</param>
/// <param name="pollingFrequency"></param>
public static void DoConsequence(string lockBlobName, Action action,
string cnStrName = "StorageConnectionString",
string containerName = "leasesContainer", TimeSpan? pollingFrequency = null)
{
//http://www.windowsazure.com/en-us/develop/net/how-to-guides/blob-storage/
// Формат пути к блобу
//http://<storage account>.blob.core.windows.net/<container>/<blob>
// Блобовский аккаунт
var account = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings[cnStrName].ConnectionString); //CloudStorageAccount.Parse("UseDevelopmentStorage=true"); // Не работает на SDK 2.2 // or your real connection string
var blobs = account.CreateCloudBlobClient();
// Контейнер - типа папки
var container = blobs
.GetContainerReference(ConfigurationManager.AppSettings[containerName]);
container.CreateIfNotExists();
var blob = container.GetBlockBlobReference(lockBlobName);
bool jobDone = false;
while (!jobDone)
{
using (var arl = new AutoRenewLease(blob))
{
if (arl.HasLease)
{
// Some Sync Work here
action();
jobDone = true;
}
else
{
Thread.Sleep(pollingFrequency ?? TimeSpan.FromMilliseconds(300));
}
}
}
}
public static void DoEvery(CloudBlockBlob blob, TimeSpan interval, Action action)
{
while (true)
{
var lastPerformed = DateTimeOffset.MinValue;
using (var arl = new AutoRenewLease(blob))
{
if (arl.HasLease)
{
blob.FetchAttributes();
DateTimeOffset.TryParseExact(blob.Metadata["lastPerformed"], "R", CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal, out lastPerformed);
if (DateTimeOffset.UtcNow >= lastPerformed + interval)
{
action();
lastPerformed = DateTimeOffset.UtcNow;
blob.Metadata["lastPerformed"] = lastPerformed.ToString("R");
AccessCondition ac = new AccessCondition();
ac.LeaseId = arl.leaseId;
blob.SetMetadata(ac);
}
}
}
var timeLeft = (lastPerformed + interval) - DateTimeOffset.UtcNow;
var minimum = TimeSpan.FromSeconds(5); // so we're not polling the leased blob too fast
Thread.Sleep(
timeLeft > minimum
? timeLeft
: minimum);
}
}
public AutoRenewLease(CloudBlockBlob blob)
{
this.blob = blob;
blob.Container.CreateIfNotExists();
try
{
if (!blob.Exists())
{
blob.UploadFromByteArray(new byte[0], 0, 0, AccessCondition.GenerateIfNoneMatchCondition("*"));// new BlobRequestOptions { AccessCondition = AccessCondition.IfNoneMatch("*") });
}
}
catch (StorageException e)
{
if (e.RequestInformation.HttpStatusCode != (int)HttpStatusCode.PreconditionFailed // 412 from trying to modify a blob that's leased
&& e.RequestInformation.ExtendedErrorInformation.ErrorCode != BlobErrorCodeStrings.BlobAlreadyExists
)
{
throw;
}
}
try
{
leaseId = blob.AcquireLease(TimeSpan.FromSeconds(60), null);
_accessCondition = new AccessCondition { LeaseId = leaseId };
}
catch (Exception)
{
Trace.WriteLine("==========> Lease rejected! <==========");
}
if (HasLease)
{
renewalThread = new Thread(() =>
{
while (true)
{
Thread.Sleep(TimeSpan.FromSeconds(40));
var ac = new AccessCondition();
ac.LeaseId = leaseId;
blob.RenewLease(ac);//.RenewLease(leaseId);
}
});
renewalThread.Start();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if (renewalThread != null)
{
renewalThread.Abort();
blob.ReleaseLease(_accessCondition);
renewalThread = null;
}
}
disposed = true;
}
}
~AutoRenewLease()
{
Dispose(false);
}
}
}
Here is how to use this (don't forget about setup config for blob connection string and catalog name):
// lock analog
AutoRenewLease.DoConsequence("testBlob2", () =>
{
// Some task
if (collection == 0)
{
Thread.Sleep(1000 * 2);
collection++;
}
Trace.WriteLine(tNo + " =====Collection=" + collection);
Trace.WriteLine(tNo + " =====MustBe = 1");
});
I would highly recommend modeling this through a series of messages. You can send a message (command) via Azure Service Bus to create booking. Only one consumer will process the message and you won't need a "lock". In addition, you can scale out to multiple consumers so that you can process multiple commands concurrently. Events can also be used to notify consumers of changes in state (like a booking was created or updated) and do what they need to do.

Debugging Data-Service-Request-Exception on WCF-Data-Service during add new entity

this is my service code :
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.Web;
namespace RadAppSilver.Web
{
public class DsWFS006 : DataService<WFS006Entities>
{
public DsWFS006()
{
ServiceHost host = new ServiceHost(typeof(DsWFS006));
ServiceDebugBehavior debug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
// if not found - add behavior with setting turned on
if (debug == null)
{
host.Description.Behaviors.Add(
new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
// make sure setting is turned ON
if (!debug.IncludeExceptionDetailInFaults)
{
debug.IncludeExceptionDetailInFaults = true;
}
}
host.Open();
// This method is called only once to initialize service-wide policies.
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
//config.SetEntitySetPageSize("DocDetail", 30);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
}
I need to debug when I'm going to new record to my entity error happened but update entity works fine :
private void Grid1RowEditEnded(object sender, Telerik.Windows.Controls.GridViewRowEditEndedEventArgs e)
{
if (e.EditAction == Telerik.Windows.Controls.GridView.GridViewEditAction.Commit)
{
doc.AccNo = string.IsNullOrEmpty(SelectedAcc) ? doc.AccNo : SelectedAcc;
if (e.EditOperationType == Telerik.Windows.Controls.GridView.GridViewEditOperationType.Edit)
{
service.UpdateObject(doc);
}
else if (e.EditOperationType == Telerik.Windows.Controls.GridView.GridViewEditOperationType.Insert)
{
(this.grid1.ItemsSource as VirtualQueryableCollectionView).Add(doc);
service.AddObject("DocDetail", doc);
}
service.BeginSaveChanges(OnChangesSaved, service);
}
}
private void OnChangesSaved(IAsyncResult result)
{
Dispatcher.BeginInvoke(() =>
{
service = result.AsyncState as DS1.WFS006Entities;
try
{
service.EndSaveChanges(result);
}
catch (DataServiceRequestException ex)
{
MessageBox.Show(ex.Response.ToString());
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
}
});
}
and this code include initializing service on my client :
private void SetContext()
{
service = new DSEntity();
DataServiceQuery<DS1.Accounts> queryAcc = (DataServiceQuery<DS1.Accounts>)
(service.Accounts.Select(m =>
new DS1.Accounts
{
AccNo = m.AccNo,
AccDesc = m.AccDesc
}));
queryAcc.BeginExecute(t =>
{
DataServiceQuery<DS1.Accounts> state = t.AsyncState as DataServiceQuery<DS1.Accounts>;
var executedState = state.EndExecute(t);
ObservableCollection<DS1.Accounts> data = new ObservableCollection<DS1.Accounts>();
foreach (var entity in executedState)
data.Add(entity);
AccCache = data.ToList();
}, queryAcc);
var view = new VirtualQueryableCollectionView() { LoadSize = 300, VirtualItemCount = 10000 };
view.ItemsLoading += (y, e) =>
{
DataServiceQuery<DS1.DocDetail> query = (DataServiceQuery<DS1.DocDetail>)
service.DocDetail.OrderBy(it => it.Item)
.Where<DS1.DocDetail>(it => it.DocSerNo == 91120001)
.Where(view.FilterDescriptors)
.Sort(view.SortDescriptors)
.Skip(e.StartIndex)
.Take(e.ItemCount);
query = query.IncludeTotalCount();
query.BeginExecute(
s =>
{
DataServiceQuery<DS1.DocDetail> state = s.AsyncState as DataServiceQuery<DS1.DocDetail>;
var executedState = state.EndExecute(s);
var response = executedState as QueryOperationResponse<DS1.DocDetail>;
int count = (int)response.TotalCount;
ObservableCollection<DS1.DocDetail> data = new ObservableCollection<DS1.DocDetail>();
foreach (var entity in executedState)
data.Add(entity);
var dataSource = data.ToList();
view.VirtualItemCount = count;
view.Load(e.StartIndex, dataSource);
}, query);
};
grid1.ItemsSource = view;
}
it doesn't work while add new object and exception doesn't give me any detail when I add host.open(); on constructor to show exception detail the service has been stop.
Include all the option for debugging the wcf service
1.Apply the following attribute to your service class
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
Override the following two methods in your service class
a. protected override void OnStartProcessingRequest(ProcessRequestArgs args)
b,protected override void HandleException(HandleExceptionArgs args)
set the break points on these two methods and see what type of exception.

Categories

Resources