Xamarin.IOS UserData from Parse - c#

I am trying to make a project where Parse.com is storing my data.
I have two classes:
User and
UserData.
When running my code it uses the objectID from UserData, however I would like it to get the object from UserData by using the username of the current user, which I can fetch with this code:
var curUser = ParseUser.CurrentUser.Username.ToString ();
My UserData class contains the a random ObjectID, username which is simlar to the one in the User class and also the data rows.
My code currently works with my single user as I have specified the user objectID in the code right now ("dpLevcJwVP") , but I don't know how to get any else users data as said before, by using the currents users username.
My code so far which gets the data:
public async void Data()
{
ParseQuery<ParseObject> query = ParseObject.GetQuery("UserData");
ParseObject userData = await query.GetAsync ("dpLevcJwVP");
var dataString = userData.Get<string> ("myDataRow");
Console.WriteLine ("Data fetched: " + dataString);
}

Problem solved.
Used the following code:
public async void Data()
{
var curUser = ParseUser.CurrentUser.Username.ToString ();
Console.WriteLine ("User: " + curUser);
var query = ParseObject.GetQuery("UserData")
.WhereEqualTo("username", curUser);
IEnumerable<ParseObject> results = await query.FindAsync();
ParseObject userData = await query.FirstAsync ();
}

Related

C# / Azure AD / Graph API - set additional user attributes with Open Extensions

I'm trying to add some custom attributes to my newly created user objects in my Azure Active Directory with Microsoft Graph.
My code looks like this:
public async Task addUser(string firstName, string lastName)
{
var mail = firstName.ToLower() + "." + lastName.ToLower() + "#mail.com";
var user = new User
{
AccountEnabled = true,
UserPrincipalName = mail,
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = randomString(10) // I wrote a dedicated function here
},
};
var res = await graphServiceClient
.Users
.Request()
.AddAsync(user);
await addExtension(res.Id);
}
public async Task addExtension(string id)
{
var extension = new OpenTypeExtension
{
ExtensionName = "com.test.test", // necessary I guess
AdditionalData = new Dictionary<string, object>
{
{"NewAttribute1", "Batman"},
{"NewAttribute2" , "Spiderman"}
}
};
await graphServiceClient
.Users[id]
.Extensions
.Request()
.AddAsync(extension);
}
The error message, that I'm currently receiving is:
Message: One or more properties contains invalid values.
Inner error:
AdditionalData:
...
I've orientated myself here:
https://learn.microsoft.com/en-us/graph/api/opentypeextension-post-opentypeextension?view=graph-rest-1.0&tabs=http
I hope someone can help,
thanks!
I managed to make my program work. The code above is actually correct and is now doing fine for me, after some adjustments.
I had to read the extension seperately, as seen below. Accessing the user.Extensions property didn't work for me. Hope this helps someone in the future :)
public async Task getUserExtensions(string userID, string extensionID)
{
var extension = await configuration
.configure()
.Users[userID]
.Extensions[extensionID]
.Request()
.GetAsync();
foreach (var item in extension.AdditionalData)
{
Console.WriteLine($"{item.Key} | {item.Value}");
}
}

async and await with Twitter direct_messages/events using LinqToTwitter

I'm really stuck in this for days. I'm using LinqToTwitter with ASP.Net C#
I'm trying to get the new DirectMessages work, I followed the examples but with no luck.
I want the function to work on Button click, so what I tried is:
BtnClick:
`
protected void Btn1_Click(object sender, EventArgs e)
{
string x = MyTest().Result;
}
`
MyTest:
`
static async Task<string> mytest()
{
AspNetAuthorizer auth = DoAuthorization();
var twitterCtx = new TwitterContext(auth);
List<DMEvent> AllDmEvents = new List<DMEvent>();
string Cursor;
DirectMessageEvents dmResponse =
await
(from dm in twitterCtx.DirectMessageEvents
where dm.Type == DirectMessageEventsType.List &&
dm.Count == 10
select dm)
.SingleOrDefaultAsync(); //In debugging mode, after this line is executed, it will go away and keep loading forever and never come back
AllDmEvents.AddRange(dmResponse.Value.DMEvents);
Cursor = dmResponse.Value.NextCursor;
string xxx = (JsonConvert.SerializeObject(AllDmEvents, Formatting.None));
return xxx;
}
`
DoAuthorization:
`
static AspNetAuthorizer DoAuthorization()
{
AspNetAuthorizer auth = new AspNetAuthorizer();
auth = new AspNetAuthorizer
{
CredentialStore = new SessionStateCredentialStore
{
ConsumerKey = "MyConsumerKey",
ConsumerSecret = "MyConsumerSecret ",
OAuthToken = "MyOAuthToken ",
OAuthTokenSecret = "MyOAuthTokenSecret ",
ScreenName = "MyUserName",
UserID = 12345678
}
};
return auth;
}`
Any help would be SO much appreciated!
The DoAuthorization() in your code looks like it came from the Console sample and that won't work with ASP.NET. The reason is that ASP.NET is stateless and the OAuth process brings you to the Twitter site and back. So, you have to break up the authorization into two pieces: Begin and Complete.
I'm guessing that you're using ASP.NET MVC, but the concept is similar (but different) if you're using WebForms). Here's the Begin part:
public class OAuthController : AsyncController
{
public ActionResult Index()
{
return View();
}
public async Task<ActionResult> BeginAsync()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"]
}
};
Notice that it uses an MvcAuthorizer, populating credentials. Once you have the MvcAuthorizer instance, redirect the user to Twitter for authorization, like this:
string twitterCallbackUrl = Request.Url.ToString().Replace("Begin", "Complete");
return await auth.BeginAuthorizationAsync(new Uri(twitterCallbackUrl));
}
That send the user to the Twitter authorization page, where they give your app permission to operate on their behalf. Twitter will redirect the user back to twitterCallback, which is why the code above modified the URL to replace the Begin with Complete in your URL. So, Twitter redirect the user back to your app, which calls the CompleteAsync() action below:
public async Task<ActionResult> CompleteAsync()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
await auth.CompleteAuthorizeAsync(Request.Url);
// This is how you access credentials after authorization.
// The oauthToken and oauthTokenSecret do not expire.
// You can use the userID to associate the credentials with the user.
// You can save credentials any way you want - database,
// isolated storage, etc. - it's up to you.
// You can retrieve and load all 4 credentials on subsequent
// queries to avoid the need to re-authorize.
// When you've loaded all 4 credentials, LINQ to Twitter will let
// you make queries without re-authorizing.
//
//var credentials = auth.CredentialStore;
//string oauthToken = credentials.OAuthToken;
//string oauthTokenSecret = credentials.OAuthTokenSecret;
//string screenName = credentials.ScreenName;
//ulong userID = credentials.UserID;
//
return RedirectToAction("Index", "Home");
}
Now that your app has the user's permissions, grab their tokens and hold them for subsequent queries so you don't have to continue the OAuth process every time the user wants to use your app. Please see the notes in the code on how to get those credentials.
Now, when you want to perform a query, instantiate an MvcAuthorizer, like this:
static async Task<string> mytest()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
var twitterCtx = new TwitterContext(auth);
List<DMEvent> AllDmEvents = new List<DMEvent>();
string Cursor;
DirectMessageEvents dmResponse =
await
(from dm in twitterCtx.DirectMessageEvents
where dm.Type == DirectMessageEventsType.List &&
dm.Count == 10
select dm)
.SingleOrDefaultAsync(); //In debugging mode, after this line is executed, it will go away and keep loading forever and never come back
AllDmEvents.AddRange(dmResponse.Value.DMEvents);
Cursor = dmResponse.Value.NextCursor;
string xxx = (JsonConvert.SerializeObject(AllDmEvents, Formatting.None));
return xxx;
}
You can see how the first statement of your modified myTest() method instantiates MvcAuthorizer with SessionStateCredentialStore, holding your credentials.
Finally, at the point in time where you want the user to authorize your app with Twitter (log in, on first query, or any other timing of your choice), check to see whether they're already authorized and re-direct if not, like this:
public ActionResult Index()
{
if (!new SessionStateCredentialStore().HasAllCredentials())
return RedirectToAction("Index", "OAuth");
return View();
}
Notice how the code above calls HasAllCredentials() on a SessionStateCredentialStore instance. I assume that you'll be adding your own logic to determine when to load the user's credentials, but wanted you to be aware of the HasAllCredentials() helper method to make it easier to know when the user must be authorized.
For more info, visit the LINQ to Twitter OAuth docs. The LINQ to Twitter source code also has Samples on how to use OAuth.

Cosmos, retrieving conversation data within MessageController

I'm trying to replace the InMemory storage with Cosmos storage provided by Azure.
I'm storing some information within the conversation data, using it within my dialogs and resetting it from my message controller if a certain command was sent.
The way I access my conversation data within a dialog is :
context.ConversationData.GetValueOrDefault<String>("varName", "");
The way I'm resetting my data from within the messageContoller is :
StateClient stateClient = activity.GetStateClient();
BotData userData = await stateClient.BotState.GetConversationDataAsync(activity.ChannelId, activity.Conversation.Id);
userData.RemoveProperty("varName");
await stateClient.BotState.SetConversationDataAsync(activity.ChannelId,
activity.Conversation.Id, userData);
The previous line of codes are working properly if I used InMemory. as soon as I switch to cosmos the resetting part of code fails. While debugging the issue I found that the conversation data object returned is never the same as the one returned from within the dialog and I was unable to reset the variables.
This is the way I'm connecting to cosmos database:
var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]);
var key = ConfigurationManager.AppSettings["DocumentDbKey"];
var store = new DocumentDbBotDataStore(uri, key);
Conversation.UpdateContainer(
builder = >{
builder.Register(c = >store).Keyed < IBotDataStore < BotData >> (AzureModule.Key_DataStore).AsSelf().SingleInstance();
builder.Register(c = >new CachingBotDataStore(store, CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency)).As < IBotDataStore < BotData >> ().AsSelf().InstancePerLifetimeScope();
});
Any idea why this is happening ?
Edit:
When using the im memory storage this code works just fine, but replacing the storage with the cosmos storage fails to retrieve the conversation data outside the dialog (the dialog gets/sets the conversation data correctly but the StateClents fails to retrieve the data correctly it returns an empty object but the weird part is that is has the same conversation ID as the one returned from the dialog)
While debugging the issue I found that the conversation data object returned is never the same as the one returned from within the dialog and I was unable to reset the variables.
Please make sure you are using same conversation when you do saving data and resetting data operations.
Besides, I do a test using the following sample code, I can save and reset conversation data as expected.
In message controller:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
if (activity.Text=="reset")
{
var message = activity as IMessageActivity;
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = new AddressKey()
{
BotId = message.Recipient.Id,
ChannelId = message.ChannelId,
UserId = message.From.Id,
ConversationId = message.Conversation.Id,
ServiceUrl = message.ServiceUrl
};
var userData = await botDataStore.LoadAsync(key, BotStoreType.BotConversationData, CancellationToken.None);
//var varName = userData.GetProperty<string>("varName");
userData.SetProperty<object>("varName", null);
await botDataStore.SaveAsync(key, BotStoreType.BotConversationData, userData, CancellationToken.None);
await botDataStore.FlushAsync(key, CancellationToken.None);
}
}
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
public class AddressKey : IAddress
{
public string BotId { get; set; }
public string ChannelId { get; set; }
public string ConversationId { get; set; }
public string ServiceUrl { get; set; }
public string UserId { get; set; }
}
In dialog:
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
// calculate something for us to return
int length = (activity.Text ?? string.Empty).Length;
var varName = "";
if (activity.Text.ToLower().Contains("hello"))
{
context.ConversationData.SetValue<string>("varName", activity.Text);
}
if (activity.Text.ToLower().Contains("getval"))
{
varName = context.ConversationData.GetValueOrDefault<string>("varName", "");
activity.Text = $"{varName} form cosmos";
}
if (activity.Text.ToLower().Contains("remove"))
{
activity.Text = "varName is removed";
}
// return our reply to the user
await context.PostAsync($"{activity.Text}");
context.Wait(MessageReceivedAsync);
}
Test steps:
After enter hello bot, can find it saved as conversation data in Cosmosdb.
After enter “reset”, can find the value of varName is reset to null.
activity.GetStateClient() is deprecated: https://github.com/Microsoft/BotBuilder/blob/a6b9ec56393d6e5a4be74b324f722b5ca8840b4a/CSharp/Library/Microsoft.Bot.Connector.Shared/ActivityEx.cs#L329
It only uses the default state service. If you are using BotBuilder-Azure for state, then your CosmosDb implementation will not be retrieved using .GetStateClient(). Please refer to #Fei's answer for how to manipulate state using DialogModule.BeginLifetimeScope or dialog.Context methods.

Xamarin, Azure, customauth and passing parameters

I am in the process of rewritting our app using Xamarin.Forms with a C# backend and I'm trying to use customauth on login. I've got it working to a point but am struggling to pass back to the Xamarin app everything I want from the backend. I'm getting the token and user id but want a bit more.
The backend code on succesfull login seems relatively straightforward:
return Ok(GetLoginResult(body));
where GetLoginResult() is:
private object GetLoginResult(IUser body)
{
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, body.username)
};
JwtSecurityToken token = AppServiceLoginHandler.CreateToken(
claims, signingKey, audience, issuer, TimeSpan.FromDays(30));
accounts account = db.accounts.Single(u => u.username.Equals(body.username));
return new LoginResult(account)
{
authenticationToken = token.RawData,
};
}
and the LoginResult class is
public class LoginResult
{
public LoginResult(accounts account)
{
Response = 200;
CustomerId = account.CustomerId;
Modules = account.Modules;
User = new LoginResultUser
{
userId = account.id,
UserName = account.UserName,
EmployeeId = account.EmployeeId
};
}
[JsonProperty(PropertyName = "Response")]
public int Response { get; set; }
etc
In the app, I'm calling the customauth as follows:
MobileServiceUser azureUser = await _client.LoginAsync("custom", JObject.FromObject(account));
The result has the token and the correct userid but how can I fill the result with the additional properties passed back by the backend? I've got the backend working and tested using postman and the results I get there are what I want but I've been unable to find out how to get it deserialized in the app.
As I known, for custom auth , MobileServiceClient.LoginAsync would invoke https://{your-app-name}.azurewebsites.net/.auth/login/custom. When using ILSPy you could find that this method would only retrieve the user.userId and authenticationToken from the response to construct the CurrentUser of your MobileServiceClient. Per my understanding, you could leverage MobileServiceClient.InvokeApiAsync to retrieve the additional user info after the user has logged in successfully. Additionally, you could try to follow this toturial for other possible approaches.
UPDATE
You could use InvokeApiAsync instead of LoginAsync to invoke the custom login endpoint directly, then retrieve the response and get the additional parameters as follows:
When logged successfully, I added a new property userName and response the client as follows:
For the client, I added a custom extension method for logging and retrieve the additional parameters as follows:
Here are the code snippet, you could refer to them:
MobileServiceLoginExtend.cs
public static class MobileServiceLoginExtend
{
public static async Task CustomLoginAsync(this MobileServiceClient client, LoginAccount account)
{
var jsonResponse = await client.InvokeApiAsync("/.auth/login/custom", JObject.FromObject(account), HttpMethod.Post, null);
//after successfully logined, construct the MobileServiceUser object with MobileServiceAuthenticationToken
client.CurrentUser = new MobileServiceUser(jsonResponse["user"]["userId"].ToString());
client.CurrentUser.MobileServiceAuthenticationToken = jsonResponse.Value<string>("authenticationToken");
//retrieve custom response parameters
string customUserName = jsonResponse["user"]["userName"].ToString();
}
}
Login processing
MobileServiceClient client = new MobileServiceClient("https://bruce-chen-002-staging.azurewebsites.net/");
var loginAccount = new LoginAccount()
{
username = "brucechen",
password = "123456"
};
await client.CustomLoginAsync(loginAccount);

Rally API: Adding Users to a Project

I'm new to the Rally world and am struggling through how to use the RallyRestAPI. There are a number of examples of how to query Rally to get back pertinent information that I have found most helpful. What I'm trying to do is create a C# command line tool to add users to a project. It appears that I use the RallyRestAPI.Create("projectpermission",some dynamic json object) interface to accomplish the creation. My problem is understanding the "some dynamic json object" part. I'm not sure how to correctly set it up. If someone has a small example of how to set it up, I would appreciate it.
Here's a code sample illustrating how to do this. Note that:
UserID running the code to create permissions must be a Workspace or Subscription Administrator
User must already have permissions in the Workspace (i.e be a Workspace User) in order for the ProjectPermission creation to succeed
namespace RestExample_AddUsersToProject {
class Program
{
static void Main(string[] args)
{
String userName = "user#company.com";
String userPassword = "topsecret";
String serverUrl = "https://rally1.rallydev.com";
String wsapiVersion = "1.38";
RallyRestApi restApi = new RallyRestApi(
userName,
userPassword,
serverUrl,
wsapiVersion
);
restApi.Headers[RallyRestApi.HeaderType.Vendor] = "Rally Software";
restApi.Headers[RallyRestApi.HeaderType.Name] = "RestExample_AddUsersToProject";
// Query for Project for which we want to add permissions
Request projectRequest = new Request("project");
projectRequest.Fetch = new List<string>()
{
"Name",
"Owner",
"State",
"Description"
};
String projectName = "Avalanche Hazard Mapping";
projectRequest.Query = new Query("Name", Query.Operator.Equals, projectName);
QueryResult queryProjectResults = restApi.Query(projectRequest);
var myProject = queryProjectResults.Results.First();
String myProjectReference = myProject["_ref"];
Console.WriteLine("Project Name: " + myProject["Name"]);
Console.WriteLine("State: " + myProject["State"]);
// Query for User for whom we wish to add ProjectPermission
Request userRequest = new Request("user");
userRequest.Fetch = new List<string>()
{
"UserName",
"Subscription",
"DisplayName"
};
// User needing the permissions
userRequest.Query = new Query("UserName", Query.Operator.Equals, "\"boromir#midearth.com\"");
QueryResult queryUserResults = restApi.Query(userRequest);
var myUser = queryUserResults.Results.First();
String myUserReference = myUser["_ref"];
Console.WriteLine("Username: " + myUser["UserName"]);
Console.WriteLine("Display Name: " + myUser["DisplayName"]);
Console.WriteLine("Subscription: " + myUser["Subscription"]);
// Setup required ProjectPermission data
DynamicJsonObject newProjectPermission = new DynamicJsonObject();
newProjectPermission["User"] = myUser;
newProjectPermission["Project"] = myProject;
newProjectPermission["Role"] = "Editor";
// Create the permission in Rally
CreateResult addProjectPermissionResult = restApi.Create("ProjectPermission", newProjectPermission);
DynamicJsonObject fetchedProjectPermission = restApi.GetByReference(addProjectPermissionResult.Reference, "Name");
Console.WriteLine("Created ProjectPermission with Role: " + fetchedProjectPermission["Name"]);
}
}
}
There are some very basic examples of CRUD + querying here:
http://developer.rallydev.com/help/rest-api-net
The general flow will always be to create a new DynamicJsonObject, set the appropriate fields and then pass that object to the Create method of an RallyRestApi.

Categories

Resources