I want to make my WinForms-App to use the SingleSign-On (SSO) feature with Microsoft Accounts.
I created a LiveApp and I'm able to Login to my App with the LiveSDK 5.4.
But everytime I click on my Login-Button the permissions list appears and I need to accept it again.
This is my code:
private const string ClientID = "{MY_CLIENT_ID}";
private LiveAuthClient liveAuthClient;
private LiveConnectClient liveConnectClient;
string[] scopes = new string[] { "wl.offline_access", "wl.emails", "wl.signin" };
private void buttonLogin_Click(object sender, EventArgs e)
{
liveAuthClient = new LiveAuthClient(ClientID);
webBrowser1.Navigate(liveAuthClient.GetLoginUrl(scopes));
}
private async void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
if (this.webBrowser1.Url.AbsoluteUri.StartsWith("https://login.live.com/oauth20_desktop.srf"))
{
AuthResult authResult = new AuthResult(this.webBrowser1.Url);
if (authResult.AuthorizeCode != null)
{
try
{
LiveConnectSession session = await liveAuthClient.ExchangeAuthCodeAsync(authResult.AuthorizeCode);
this.liveConnectClient = new LiveConnectClient(session);
LiveOperationResult meRs = await this.liveConnectClient.GetAsync("me");
dynamic meData = meRs.Result;
if(string.Equals(meData.emails.account, MyAppUser.EmailAddress))
MessageBox.Show("Successful login: " + meData.name);
}
catch (LiveAuthException aex)
{
MessageBox.Show("Failed to retrieve access token. Error: " + aex.Message);
}
catch (LiveConnectException cex)
{
MessageBox.Show("Failed to retrieve the user's data. Error: " + cex.Message);
}
}
else
{
MessageBox.Show(string.Format("Error received. Error: {0} Detail: {1}", authResult.ErrorCode, authResult.ErrorDescription));
}
}
}
What I need to change? I don't want the User to accept the permissions on each login.
You can use IRefreshTokenHandler to save token as following example:
public class RefreshTokenHandler : IRefreshTokenHandler
{
private string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\oneDrive\\RefreshTokenHandler\\RefreshTokenInfo.RefreshToken-me";
public Task<RefreshTokenInfo> RetrieveRefreshTokenAsync()
{
return Task.Factory.StartNew<RefreshTokenInfo>(() =>
{
if (File.Exists(path))
{
return new RefreshTokenInfo(File.ReadAllText(path));
}
return null;
});
}
public Task SaveRefreshTokenAsync(RefreshTokenInfo tokenInfo)
{
// Note:
// 1) In order to receive refresh token, wl.offline_access scope is needed.
// 2) Alternatively, we can persist the refresh token.
return Task.Factory.StartNew(() =>
{
if (File.Exists(path)) File.Delete(path);
if (!Directory.Exists(Path.GetDirectoryName(path))) Directory.CreateDirectory(Path.GetDirectoryName(path));
File.AppendAllText(path, tokenInfo.RefreshToken);
});
}
}
after that you get session as following:
RefreshTokenHandler handler = new RefreshTokenHandler();
liveAuthClient = new LiveAuthClient(ClientID, handler);
var Session = liveAuthClient.InitializeAsync(scopes).Result.Session;
if (Session == null)
{
webBrowser1.Navigate(liveAuthClient.GetLoginUrl(scopes));
}
else
{
try
{
this.liveConnectClient = new LiveConnectClient(Session);
LiveOperationResult meRs = await this.liveConnectClient.GetAsync("me");
dynamic meData = meRs.Result;
if (string.Equals(meData.emails.account, MyAppUser.EmailAddress))
MessageBox.Show("Successful login: " + meData.name);
}
catch (LiveAuthException aex)
{
MessageBox.Show("Failed to retrieve access token. Error: " + aex.Message);
}
catch (LiveConnectException cex)
{
MessageBox.Show("Failed to retrieve the user's data. Error: " + cex.Message);
}
}
I've only used this API in Objective C, but I had to follow two steps.
Use the wl.offline_access scope. (Which you're already doing)
You only show the login screen if the sessions object is null. If your session object is already populated, you can proceed as you would if the sign in was successful.
Related
Hi guy's i'm trying to figure out a way to display a DisplayAlert Popup when Someone entered the Wrong details into the Login Process.
Issue is, The login's a little "Weird" I'm not comparing against a Database i'm comparing against a List of Customers I get from a APi So I have to loop threw to then find if the detail's are correct.
I have a login Phase 1() which Checks against the Wordpress API but I want to have this be able to notify on Phase 1 and 2, Phase 1 is a Username = Username Password = Password Where phase 2 is just a Username = Username , I know it's not secure The Login is more of a Formality then anything.
public async void Login_Phase1()
{
try
{
#region Login Phase 1
var client = new WordPressClient("http://XXX.co.za/wp-json/");
client.AuthMethod = AuthMethod.JWT;
try
{
await client.RequestJWToken(Usernamelabel.Text, Password.Text);
}
catch (Exception e)
{
await App.Current.MainPage.DisplayAlert("Something Went wrong", e.ToString(), "OK");
}
var x = client;
var isValidToken = await client.IsValidJWToken();
WpApiCredentials.token = client.GetToken();
if (isValidToken)
{
Login_Phase2();
}
else
{
await App.Current.MainPage.DisplayAlert("Detail's are Incorect", "Token not Found", "OK");
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
#endregion
}
public void Login_Phase2()
{
try
{
#region login Phase 2
var list = FetchCustomers.customers.ToList();
foreach (var user in list)
{
if (user.username == Usernamelabel.Text)
{
Preferences.Set("CId", user.id.ToString());
Preferences.Set("Token", WpApiCredentials.token);
Preferences.Set("CUsername", user.username);
Preferences.Set("CEmail", user.email);
Users.Loggedin = true;
Application.Current.SavePropertiesAsync();
App.Current.MainPage.DisplayAlert("Complete", "Login Process Complete, Enjoy", "OK");
App.Current.MainPage = new Home("Mica Market");
}
//Want to add a Display popup Here to say the information is entered incorrectly, but
not have it repeat 200 Time's
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
#endregion
}
Fetching all the Customers to check against
private async void ExtractWooData(List<Customer> x)
{
try
{
#region FetchC
RestAPI rest = new RestAPI("http://xxxxxx/wp-json/wc/v3/", "ck_a25xxxxxxxxxxx0", "cs_8xxxxxxxx8xxxx");
WCObject wc = new WCObject(rest);
int pageNum = 1;
var isNull = false;
List<Customer> oldlist;
while (!isNull)
{
var page = pageNum.ToString();
x = await wc.Customer.GetAll(new Dictionary<string, string>() {
{
"page", page
}, {
"per_page", "100"
}
});
oldlist = FetchCustomers.customers ?? new List<Customer>();
if (x.Count == 0)
{
break;
}
else
{
//1st loop customers needs to = 100
//2nd loop oldist needs to = 40+
//If count = 0 then => Combine Customers + Oldist
pageNum++;
FetchCustomers.customers = oldlist.Union(x).ToList();
}
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
#endregion
}
Any Advice?
you can replace the foreach with a LINQ query
// find the first match
var found = list.Where(user => user.username == Usernamelabel.Text).FirstOrDefault();
if (found != null)
{
// set preferences and navigation
}
else
{
// DisplayAlert
}
I am trying to create a Xamarin application using Azure computer vision API, I got the API key and endpoint URL whenever i click a picture and set in image view and then describe image function not working and i am not getting output captions, my code is below:
private async void Button_Clicked(object sender, EventArgs e)
{
await CrossMedia.Current.Initialize();
try
{
if(!CrossMedia.Current.IsTakePhotoSupported&&!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert("INFO", "CAMERA NOT AVAILABEL", "OK");
}
else
{
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory="Images",
Name="test.jpg"
});
if (file==null)
{
await DisplayAlert("ERROR", "FILE NOT FOUND", "OK");
return;
}
img.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
var visionapi = new ComputerVisionClient(new ApiKeyServiceClientCredentials(""));
visionapi.Endpoint = "";
var desc = await visionapi.DescribeImageInStreamAsync(file.GetStream());
foreach (var tag in desc.Captions)
{
cap.Text = cap.Text + "\n" + tag;
}
}
}
catch(Exception )
{
await DisplayAlert("", "ERROR", "OK");
}
}
DescribeImageInStreamAsync functon is not working it is moving into catch block after few minutes with the below error:
Microsoft.Azure.CognitiveServices.Vision.ComputerVisionErrororException: Operation returned an invalid status code 'Not Found'
Exception
I am creating a Xamarin Form PCL project for Android and IOS.
Is this possible to display multiple permission at once on the screen? My App is using Location, Storage and Camera permission. From my current code, this is displaying permission popup one by one on the different page like before use of camera i display camera permission popup. As I know three permission required for my App so i want to display a single popup for all three permission.
Below is my code for storage permission.
public static async Task<dynamic> CheckStoragePermission()
{
var result = "";
try
{
var Storagestatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);
if (Storagestatus != PermissionStatus.Granted)
{
await Utils.CheckPermissions(Plugin.Permissions.Abstractions.Permission.Storage);
}
}
catch (Exception ex)
{
error(ex.Message, Convert.ToString(ex.InnerException), ex.Source, ex.StackTrace);
}
return result;
}
Hope someone did this before in xamarin forms, I will thank for your help for this.
You could try using the following code to request multiple permissions at one time:
private async void Button_Clicked(object sender, EventArgs e)
{
await GetPermissions();
}
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.LocationAlways,
Permission.LocationWhenInUse,
Permission.Storage,
Permission.Camera
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == PermissionStatus.Granted || status == PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
}
return permissionsGranted;
}
I want to create a service for Wifi Direct. If I try to add Reference, I don't see core->windows option in VS2013. I have updated the winSDK.
How do I add the Windows.Devices.WifiDirect api ?
you can use
public sealed class WiFiDirectDevice : IDisposable
this is a sample code to handle connections
Windows.Devices.WiFiDirect.WiFiDirectDevice wfdDevice;
private async System.Threading.Tasks.Task<String> Connect(string deviceId)
{
string result = "";
try
{
// No device Id specified.
if (String.IsNullOrEmpty(deviceId)) { return "Please specify a Wi- Fi Direct device Id."; }
// Connect to the selected Wi-Fi Direct device.
wfdDevice = await Windows.Devices.WiFiDirect.WiFiDirectDevice.FromIdAsync(deviceId);
if (wfdDevice == null)
{
result = "Connection to " + deviceId + " failed.";
}
// Register for connection status change notification.
wfdDevice.ConnectionStatusChanged += new TypedEventHandler<Windows.Devices.WiFiDirect.WiFiDirectDevice, object>(OnConnectionChanged);
// Get the EndpointPair information.
var EndpointPairCollection = wfdDevice.GetConnectionEndpointPairs();
if (EndpointPairCollection.Count > 0)
{
var endpointPair = EndpointPairCollection[0];
result = "Local IP address " + endpointPair.LocalHostName.ToString() +
" connected to remote IP address " + endpointPair.RemoteHostName.ToString();
}
else
{
result = "Connection to " + deviceId + " failed.";
}
}
catch (Exception err)
{
// Handle error.
result = "Error occurred: " + err.Message;
}
return result;
}
private void OnConnectionChanged(object sender, object arg)
{
Windows.Devices.WiFiDirect.WiFiDirectConnectionStatus status =
(Windows.Devices.WiFiDirect.WiFiDirectConnectionStatus)arg;
if (status == Windows.Devices.WiFiDirect.WiFiDirectConnectionStatus.Connected)
{
// Connection successful.
}
else
{
// Disconnected.
Disconnect();
}
}
private void Disconnect()
{
if (wfdDevice != null)
{
wfdDevice.Dispose();
}
}
I am trying to Configure my IIS programmatically following the steps on this
msdn guide
the only difference i made was switching to winforms instead of console..
and variables instead of function parameters.
however the code throws an exception when i try to set the singleproperty value...
here is my code..
string metabasePath = "IIS://localhost/W3SVC/1234", propertyName = "ServerBindings";
object newValue = " :8080:";
try
{
DirectoryEntry path = new DirectoryEntry(metabasePath);
//when i try to retrieve the old value,it returns a null
PropertyValueCollection propValues = path.Properties[propertyName];
MessageBox.Show("7");
//the code throws an exception after messagebox,
//kinda old school debuging
path.Properties[propertyName][0] = newValue;
path.CommitChanges();
lblerror.Text = "Done";
}
catch (Exception ex)
{
if ("HRESULT 0x80005006" == ex.Message)
lblerror.Text = " Property does not exist at ";
else
lblerror.Text = "Failed in SetSingleProperty "+ ex.Message.ToString();
}
The following 'helper' methods (SetServerBinding and RemoveServerBinding) should be of use:
static void Main(string[] args)
{
using(DirectoryEntry site = new DirectoryEntry("IIS://Localhost/W3SVC/1234"))
{
SetServerBinding(":8080:", site);
RemoveServerBinding(":8080:", site);
RemoveServerBinding("172.16.4.99:8087:somesite.com", site);
SetServerBinding("172.16.4.99:8087:somesite.com", site);
}
}
public static void SetServerBinding(string binding, DirectoryEntry site)
{
if(site.Properties["ServerBindings"].Contains(binding))
{
site.Properties["ServerBindings"].Remove(binding);
return;
}
site.Properties["ServerBindings"].Add(binding);
site.CommitChanges();
}
public static void RemoveServerBinding(string binding, DirectoryEntry site)
{
if (site.Properties["ServerBindings"].Contains(binding))
{
site.Properties["ServerBindings"].Remove(binding);
}
site.CommitChanges();
}