Unable to find Table in Azure Mobile Service Win Phone 8.1 - c#

I am currently trying to implement Azure Mobile Service into my Windows Phone 8.1 application.
I followed documentation on it Azure.Microsoft.com:
Get started with Mobile Services and I created a new Windows Phone 8.1 project with the service. I tried making a new table with the exact configuration as the sample as well as a new Class to matching the table name & fields. Below is the original code, I changed all of the TodoItem into 'Test'
I keep getting the error:
Error: Table 'Test' does not exist
I tried making both a Javascript and .NET version for back-end but they still failed
Am I unable to find my table because I am missing a step?
sealed partial class MainPage : Page
{
private MobileServiceCollection<Test, Test> items;
private IMobileServiceTable<Test> todoTable = App.MobileService.GetTable<Test>();
public MainPage()
{
this.InitializeComponent();
}
private async Task InsertTodoItem(Test todoItem)
{
await todoTable.InsertAsync(todoItem);
items.Add(todoItem);
}
private async Task RefreshTodoItems()
{
MobileServiceInvalidOperationException exception = null;
try
{
items = await todoTable
.Where(todoItem => todoItem.Complete == false)
.ToCollectionAsync();
}
catch (MobileServiceInvalidOperationException e)
{
exception = e;
}
if (exception != null)
{
await new MessageDialog(exception.Message, "Error loading items").ShowAsync();
}
else
{
ListItems.ItemsSource = items;
this.ButtonSave.IsEnabled = true;
}
}
private async Task UpdateCheckedTodoItem(Test item)
{
await todoTable.UpdateAsync(item);
items.Remove(item);
ListItems.Focus(Windows.UI.Xaml.FocusState.Unfocused);
}
private async void ButtonRefresh_Click(object sender, RoutedEventArgs e)
{
ButtonRefresh.IsEnabled = false;
await RefreshTodoItems();
ButtonRefresh.IsEnabled = true;
}
private async void ButtonSave_Click(object sender, RoutedEventArgs e)
{
var todoItem = new Test { Text = TextInput.Text };
await InsertTodoItem(todoItem);
}
private async void CheckBoxComplete_Checked(object sender, RoutedEventArgs e)
{
CheckBox cb = (CheckBox)sender;
Test item = cb.DataContext as Test;
await UpdateCheckedTodoItem(item);
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await RefreshTodoItems();
}
}

For Javascript backend:
Go into the azure portal and select your mobile service. Go to the tab that says data. Click add a table name the table Test.
For .Net:
Open the project in Visual Studio. Add your Test class to the DataObjects folder. Right click the Controllers folder -> add -> controller. Select Microsoft Azure Mobile Services Table Controller. Chose your Test class for the model class and there should only be one option for the data context class.

You follow this article
Get started with Mobile Services
and you saw this
and with this you got the source code. This way you got two projects:
The .Net BackEnd project
The client app project
and when you did the changes, you only changed the client app project (because the MainPage belongs to the client app).
If you changed the TodoItem class to Test class in client app project, you need to do the same for the .NET Project, which requires the changes:
change the TodoItemController to TestController
change the TodoItem to Test
do a clean, then build and if do not have any error you can publish to Azure.
To help understand a bit it, I recommend to see the following samples
Connecting a Menu App to Azure Mobile Service
this article contains a step by step to create a simple backend like you are doing and provides tips that will help you.
How to create the Azure Mobile Service in Azure Portal
AzureMobileServices: Samples to help developers to use Azure Mobile Services

Related

Correct Xamarin Forms Shell initializing with async data loading

I am working on a rather complex xamarin forms app for a while now and now I came over a problem related to the async initialization of the app. Some context before I come to the problem.
I am using the current version of Xamarin Forms, my main target is
xamarin android
I am building on top of the xamarin forms Shell
pattern
I am using a sqlite database for the main part of the apps
configuration
The app layout is mainly dependent on the configuration stored in the sqlite database (what I call a data driven app)
Therefore I am building the whole shell page layout not in xaml but in code behind of the AppShell.xaml.cs - in the constructure to be concrete (first weird point in my personal opinion).
So first remarkable point here - I need the fully loaded configuration BEFORE the AppShell is initiated.
At first a started with a mockup data service where the whole config was inside a large mocked object so it ran fully synchronized - everything perfect!
After switching over to the sqlite implementation where I am using async methods the problem started to show up because I try to load the configuration in the constructor (second weird point because such a task should never be part of a constructor in my point of view)
So my constructor of AppShellView.xaml looks like this.
public App()
{
InitializeComponent();
InitApp().SafeFireAndForget(onException: ErrorHandler);
MainPage = new AppShellView();
}
the InitApp Method where the database is queried looks like this.
private async Task InitApp()
{
_settingsService = ViewModelLocator.Resolve<ISettingsService>();
ViewModelLocator.UpdateDependencies(_settingsService.UseDemoMode);
_dataService = ViewModelLocator.Resolve<IDataService>();
ActiveConfiguration = await _dataService.GetActiveConfigurationAsync().ConfigureAwait(false);
//MainPage = new AppShellView(); this was added to reload the MainPage after the config was fully loaded
}
what obviously happens is that the MainPage = new AppShellView() in the App's constructor is called before the config is loaded - because its called in a fireandforget way. Therefore the following construction of the AppShellView does not work as intendet because the pages cannot be added because of the missing config. I hope this is clear so far.
To overcome this issue I added another MainPage = new AppShelLView() as last step of the InitApp method.
The constructor of the AppShellView looks like this:
public AppShellView()
{
InitializeComponent();
BuildMainNavigation();
BuildSettingsNavigation();
InitRoutes();
this.CurrentItem.CurrentItem = startSection;
}
This seems to work on thirst sight but triggers side effects when the app is started from AppLink Shortcuts and not to forget I ended up initializing the same object again and again which causes performance issues and simply smells...
So I hope I made my point clear so far - I know that I have a view issues in my implementation but I simply don't see the correct way of doing it.
What I would naturally would try to do is doing the configuration loading in the android init part behind the splash screen which I implemented like this: https://learn.microsoft.com/en-us/xamarin/android/user-interface/splash-screen but I also found no way to pass the data from the android Activity to the App class.
To sum up and ask a concrete question:
What is the best practice way of loading async configuration BEFORE initializing the Shell
#Jason: thanks for your fast response. So this idea seems promising, sounds like another Splash Screen but thats ok.
I tried that - for the initial setup that works fine.
App's constructor is simplified to this:
public App()
{
InitializeComponent();
MainPage = new Splashscreen();
}
The OnStart looks like this now:
protected async override void OnStart()
{
base.OnStart();
if (!IsInitiated)
{
_settingsService = ViewModelLocator.Resolve<ISettingsService>();
ViewModelLocator.UpdateDependencies(_settingsService.UseDemoMode);
_dataService = ViewModelLocator.Resolve<IDataService>();
ActiveConfiguration = await _dataService.GetActiveConfigurationAsync().ConfigureAwait(true);
MainPage = new AppShellView();
App.Current.UserAppTheme = _settingsService.OSAppTheme;
}
else
{
App.Current.UserAppTheme = _settingsService.OSAppTheme;
}
base.OnResume();
}
But I have app link functionality, where OnAppLinkRequestReceived is called.
protected override async void OnAppLinkRequestReceived(Uri uri)
{
if(MainPage is Splashscreen)
{
MainPage = new AppShellView();
}
IsInitiated = true;
var targets = uri.ToString().Replace(GlobalSetting.AppShortcutUriBase, "");
var subtargets = targets.Split('/');
App.CurrentPageId = new Guid(subtargets[0]);
if(subtargets.Length > 1 && !string.IsNullOrWhiteSpace(subtargets[1])){
await Shell.Current.GoToAsync($"//{App.CurrentPageId}?buildingPartId={new Guid(subtargets[1])}");
}
else
{
await Shell.Current.GoToAsync("//" + App.CurrentPageId);
}
}
The Problem is that its called before OnStart. So its calling the correct page first but the reinit in OnStarts resets the app to base.
I could overcome this issue with performing the init only of OnAppLinkRequestReceived is not called but then I have one last issue.
I call App.Current.UserAppTheme = _settingsService.OSAppTheme; as displayed above inside OnStart end the call inside the else black is failing with NullpointerException because App.Current seems to be null in this case. Do you know why?
Here are the final code bits that made the whole thing work. The key aspects are as follows:
Add another SplashScreen which is initiated inside App.xaml.cs constructor
Perform the long running async method in the OnStart()
Perform path based navigation which is triggered by an AppLinkRequest also inside the OnStart after storing the AppLinkRequest Uri inside a property
public App()
{
InitializeComponent();
_settingsService = ViewModelLocator.Resolve<ISettingsService>();
ViewModelLocator.UpdateDependencies(_settingsService.UseDemoMode);
_dataService = ViewModelLocator.Resolve<IDataService>();
AppLinkUri = null;
MainPage = new SplashScreen();
}
private async Task InitApp()
{
ActiveConfiguration = await _dataService.GetActiveConfigurationAsync().ConfigureAwait(true);
}
protected override async void OnStart()
{
base.OnStart();
if (ActiveConfiguration == null)
{
await InitApp().ConfigureAwait(true);
}
MainPage = new AppShellView();
if (AppLinkUri != null)
{
var targets = AppLinkUri.ToString().Replace(GlobalSetting.AppShortcutUriBase, "");
var subtargets = targets.Split('/');
App.CurrentPageId = new Guid(subtargets[0]);
if (subtargets.Length > 1 && !string.IsNullOrWhiteSpace(subtargets[1]))
{
await Shell.Current.GoToAsync($"//{App.CurrentPageId}?buildingPartId={new Guid(subtargets[1])}");
}
else
{
await Shell.Current.GoToAsync("//" + App.CurrentPageId);
}
}
base.OnResume();
}
protected override void OnAppLinkRequestReceived(Uri uri)
{
AppLinkUri = uri;
}

Redis Cache - A blocking operation was interrupted by a call to WSACancelBlockingCall

I have an ASP.NET Web Forms Page with the following code:
public partial class MyAspNetWebFormPage : System.Web.UI.Page{
protected void Page_Load(object sender, EventArgs e){
ClearRedisCache("RedisCacheConnectionString_01");
ClearRedisCache("RedisCacheConnectionString_02");
}
private void ClearRedisCache(string redisConnectionString){
var serverName = redisConnectionString.Split(',')[0];
using (var redis = ConnectionMultiplexer.Connect(redisConnectionString)){
var server = redis.GetServer(serverName);
server.FlushAllDatabases(CommandFlags.None);
redis.Close(true); // this was added as an effort to fix the problem but doesn't work
// Another effort to make it work
// Added after receiving the error
do {
Thread.Sleep(1000);
} while (redis.IsConnected);
}
}
}
When I run this on my local box it seems to work perfectly fine. However, when I run it in our Azure Environment it throws an exception with the following message:
A blocking operation was interrupted by a call to WSACancelBlockingCall
Other examples that I've seen are caching the connection and keeping it open. Is that how I'm suppose to implement redis cache?
This code is executed from an Admin Dashboard that is completely disconnected from the Consumer Site. The Admin Dashboard doesn't use Redis Cache other than to clear it.
Any ideas are greatly appreciated. Thank you in advance.
Looking into this further and playing with the settings here's what worked for me:
public partial class MyAspNetWebFormPage : System.Web.UI.Page{
protected void Page_Load(object sender, EventArgs e){
ClearRedisCache("RedisCacheConnectionString_01");
ClearRedisCache("RedisCacheConnectionString_02");
}
private void ClearRedisCache(string redisConnectionString){
string securityProtocol = (SecurityProtocol)Enum.Parse(typeof(SecurityProtocol), securityProtocol);
var options = ConfigurationOptions.Parse(redisConnectionString);
options.SslProtocols = System.Security.authentication.SslProtocols.Tls12;
options.Ssl = true;
options.AllowAdmin = true;
options.AbortOnConnectFail = false;
var serverName = redisConnectionString.Split(',')[0];
using (var redis = ConnectionMultiplexer.Connect(options)){
var server = redis.GetServer(serverName);
server.FlushAllDatabases(CommandFlags.None);
}
}
}

WPF Application does not seem to be receiving a response

I currently have two separate projects, one is a WPF application with .NET Framework 4.7.2 and the other is a console application with ASP.NET Core 3.1. The console application used to be .NET 4.7.2 as well however I have just finished moving it to Core.
The WPF Application sends an object to the console application and the console application does some stuff with it and returns a response. My issue currently is that the WPF application successfully sends the object, the console application receives it and does what it needs, however when it sends the response, the WPF application just hangs and must be completely stopped. Here is the code for both:
WPF Application (was working perfectly fine before moving the console to core):
static async Task SendRequest(UploadDetails u)
{
System.Diagnostics.Debug.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(u));
HttpResponseMessage response = await _client.PostAsJsonAsync(_clientUrl, u);
if (response.IsSuccessStatusCode)
{
var responseLink = await response.Content.ReadAsStringAsync();
responseLink = responseLink.Replace("\"", "");
System.Diagnostics.Debug.WriteLine("SUCCESSFUL UPLOAD"); //TODO: Add response
Messenger.Default.Send(new NotificationMessage(responseLink));
}
else
{
System.Diagnostics.Debug.WriteLine("UNSUCCESSFUL UPLOAD"); //TODO: Add response
}
}
Console Application (even sends correct response with postman):
[HttpPost("upload")]
public ActionResult Upload(UploadDetails data)
{
try
{
Task.Factory.StartNew(() => { _Uploader.Upload(data); });
return Ok("Started");
}
catch (Exception e)
{
return NotFound();
}
}
Any help would be greatly appreciated.
Without further information it is hard to determine the actual problem....
But just by looking at the code provided I see one problem:
You are sending JSON yet your action is not inspecting the body.
So I would make one change:
1 Your parameter should have an attribute [FromBody] like this:
[HttpPost]
public ActionResult Upload([FromBody] UploadDetails data)
Also you have to make sure your HttpClient has the correct headers when initialized like this:
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
The last thing I can think of is that you are calling your async method wrong in the WPF application....
For example this would hang on the "await _client.PostAsJsonAsync....." line
private void Button_Click(object sender, RoutedEventArgs e)
{
SendRequest(new UploadDetails { }).Wait();
}
This would NOT hang:
private async void Button_Click(object sender, RoutedEventArgs e)
{
await SendRequest(new UploadDetails { });
}
The reason is that the first one would block the main thread and the second one would not.
But without the code that calls the SendRquest it is impossible to know.

Validate internet connection or Azure service - Xamarin

I have a application develop in Xamarin (Cross Platform) that now run great!! But always need internet connection.
If internet connection will fail, my app suffers an unexpected shutdown. I would like controle this.
First I have "AzureDataService" class:
public class AzureDataService
{
//Conexion to backend
public MobileServiceClient MobileService { get; set; }
//Object of "Ficha" class.
IMobileServiceSyncTable<Ficha> tablaFicha;
public async Task Initialize()
{
if (isInitialized)
return;
MobileService = new MobileServiceClient("http://linkbdd");
//Save data in a local DB, later upload with internet connection
const string path = "bbddMuestra.db";
var store = new MobileServiceSQLiteStore(path);//Create DB
store.DefineTable<Ficha>();
//async initialization
await MobileService.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
//Inicializate table
tablaFicha = MobileService.GetSyncTable<Ficha>();
isInitialized = true;
}
//Here get data
public async Task<IEnumerable<Ficha>> GetData()
{
await Initialize();
await SyncFicha();
//Select data...
return await tablaFicha.OrderBy(a => a.Id).ToEnumerableAsync();
}
public async Task SyncFicha()
{
await tablaVehiculos.PullAsync("Ficha", tablaFicha.CreateQuery());
await MobileService.SyncContext.PushAsync();
}
End of "AzureDataService" class. Now the class when implement AzureDataService.
public partial class ListaFichas : ContentPage
{
public static ObservableCollection ficha;
public ListaFichas ()
{
InitializeComponent ();
ficha = new ObservableCollection();
}
protected async override void OnAppearing()
{
base.OnAppearing();
ficha.Clear();
//Next line get data from previous method of class "AzureDataService"
var ligas = await App.AzureService.GetData();
foreach(var item in ligas)
{
Ficha fi = item;
ficha.Add(fi);
}
//Here bind listview with data that previous get
lsvFichas.ItemsSource = ficha;
}
Please help me. I would like show a Display or DisplayActionSheet to inform user...But never unexpected shutdown.
Thanks!...
You have to check internet connection
Below link is useful for you
https://forums.xamarin.com/discussion/comment/276931#Comment_276931
AFAIK, if you call PushAsync to PUSH the sync content, then the list of creates, updates and Deletes against your offline tables would be sent one by one to the Azure App Service. Both PullAsync and PushAsync operations need your mobile client online.
Per my understanding, you could check the internet connection before call SyncFicha for sync your data. Also, you could just wrap your SyncFicha method with try-catch for both handling the internet connection and conflict when you pushing the offline data. I recommend that you could refer to the following tutorials from adrian hall's book as follows:
Detecting Connection State
Use Xam.Plugin.Connectivity for checking connectivity state as follows:
await Initialize();
if (!(await CrossConnectivity.Current.IsRemoteReachable(Client.MobileAppUri.Host, 443)))
{
Debug.WriteLine($"Cannot connect to {Client.MobileAppUri} right now - offline");
return;
}
await tablaVehiculos.PullAsync("Ficha", tablaFicha.CreateQuery());
await MobileService.SyncContext.PushAsync();
Handling Conflict Resolution

Dropnet authentication behaviour on Windows Phone 7.1 and 8.0

I have a pair of Windows Phone apps that make use of Dropnet for Dropbox integration. One developed in Visual Studio Express 2012 targeting 7.1 and one in Visual Studio 2013 targeting 8.0.
Both are using Dropnet 1.9.6 and RestSharp 104.4.0 via NuGet.
The 7.1 project uses the following static class to interact with DropNet authentication (and file operations but I've excluded them for clarity).
public static class DropboxStorage
{
const string UserToken = "UserToken";
const string UserSecret = "UserSecret";
private static DropNetClient _Dropbox;
public static DropNetClient Dropbox
{
get
{
if (_Dropbox == null)
{
_Dropbox = new DropNetClient(AppKey, AppSecret);
if (IsAuthenticated)
{
_Dropbox.UserLogin = new UserLogin
{
Token = (string)IsolatedStorageSettings.ApplicationSettings[UserToken],
Secret = (string)IsolatedStorageSettings.ApplicationSettings[UserSecret]
};
}
_Dropbox.UseSandbox = true;
}
return _Dropbox;
}
}
public static bool IsAuthenticated
{
get
{
return IsolatedStorageSettings.ApplicationSettings.Contains(UserToken) &&
IsolatedStorageSettings.ApplicationSettings.Contains(UserSecret);
}
}
public static void StartAuthentication(Action<Uri> success, Action<Exception> failure)
{
Dropbox.GetTokenAsync(userLogin =>
{
var url = Dropbox.BuildAuthorizeUrl(userLogin);
if (success != null) success(new Uri(url, UriKind.RelativeOrAbsolute));
}, error =>
{
if (failure != null) failure(error);
});
}
public static void CheckAuthentication(Uri uri, Action success, Action<Exception> failure)
{
if (uri.LocalPath == "/1/oauth/authorize_submit")
{
Dropbox.GetAccessTokenAsync((accessToken) =>
{
IsolatedStorageSettings.ApplicationSettings[UserToken] = accessToken.Token;
IsolatedStorageSettings.ApplicationSettings[UserSecret] = accessToken.Secret;
IsolatedStorageSettings.ApplicationSettings.Save();
if (success != null) success();
},
(error) =>
{
if (failure != null) failure(error);
});
}
}
This is then accessed via a page with a WebBrowser control.
XAML
<phone:WebBrowser x:Name="Browser"
IsScriptEnabled="True"
Navigated="Browser_Navigated"/>
C#
public partial class DropboxPage : PhoneApplicationPage
{
public DropboxPage()
{
InitializeComponent();
DropboxStorage.StartAuthentication(
uri => Browser.Navigate(uri),
ex => ShowException(ex));
}
public void Browser_Navigated(object sender, NavigationEventArgs e)
{
Debug.WriteLine(e.Uri.OriginalString);
DropboxStorage.CheckAuthentication(
e.Uri,
() => NavigationService.GoBack(),
ex => ShowException(ex));
}
private void ShowException(Exception e)
{
MessageBox.Show(e.Message);
NavigationService.GoBack();
}
}
The Dropbox authentication web pages are displayed
Sign in
Allow app access
Success, app connected
and the code determines that authentication has been successful when the Dropbox url contains /1/oauth/authorize_submit.
This all works perfectly, however the 8.0 project behaves a little differently.
The first difference is the url returned by the BuildAuthorizeUrl call.
7.1 https://www.dropbox.com/1/oauth/authorize?oauth_token=<token>
8.0 https://api.dropbox.com/1/oauth/authorize?oauth_token=<token>
The second difference is that the Dropbox url doesn't change from /authorize?oauth_token= to /authorize_submit once the app has been connected so GetAccessTokenAsync is never called and the user token and user secret aren't stored.
My investigations to date suggest a couple of ways to fix this that aren't ideal
Remove the url validation from around the GetAccessTokenAsync call
and eat the resulting DropboxExceptions
Add a callback url to the initial BuildAuthorizeUrl call.
I'm currently doing 1. just to get things up and running but obviously this isn't a long term solution. I'd prefer to avoid using a callback url as it seems like an over complication for a mobile app.
What I'm after is a way of getting the 8.0 project to behave in the same way as the 7.1 project. I've had a look at the Dropnet source code and that contains https://api.dropbox.com as it's base url so I'm even less clear as to how the 7.1 code is working in the first place.
The difference in behaviour is caused by the 8.0 project using System.Windows.Interactivity to convert the Navigated event into a call to a Command on the ViewModel. This seems to prevent the website and WebBrowser control interacting correctly and redirecting to https://www.dropbox.com.
Current
XAML
<phone:WebBrowser x:Name="Browser"
IsScriptEnabled="True"
Visibility="{Binding IsAuthenticated, Converter={StaticResource BoolToInvisibilityConverter}}"
Source="{Binding AuthenticateUri}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Navigated" >
<i:InvokeCommandAction Command="{Binding BrowserNavigated}"
CommandParameter="{Binding Source, ElementName=Browser}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</phone:WebBrowser>
C#
BrowserNavigated = new RelayCommand<Uri>(u =>
{
RemoteStorage.CheckAuthentication(u, () => IsAuthenticated = true, ex => ShowException(ex));
});
Corrected
XAML
<phone:WebBrowser x:Name="Browser"
IsScriptEnabled="True"
Visibility="{Binding IsAuthenticated, Converter={StaticResource BoolToInvisibilityConverter}}"
Source="{Binding AuthenticateUri}"
Navigated="Browser_Navigated"/>
C#
private void Browser_Navigated(object sender, NavigationEventArgs e)
{
ViewModel.BrowserNavigated.Execute(e.Uri);
}
In both cases the AuthenticateUri property of the view model bound to the WebBrowser Source is set by the StartAuthentication method in the DropboxStorage class.
Having added the event handler the 8.0 project works as expected.
I also started seeing this problem not too long ago. My app worked fine on WP8 up until that point. I don't remember all the details but I looked at my checkin to fix it and I think an extra page load for the first url started happening. No warning from Dropbox about the change either.
To solve it I wait for a certain url to show up in the LoadCompleted event. You use the Navigated event which I think should also work.
I would modify your event handler like this:
public void Browser_Navigated(object sender, NavigationEventArgs e)
{
if (e.Uri.AbsolutePath == "/1/oauth/authorize_submit")
{
DropboxStorage.CheckAuthentication(
e.Uri,
() => NavigationService.GoBack(),
ex => ShowException(ex));
}
}

Categories

Resources