I have two tables : Users & Profiles. A user has one profile (1:1), a profile can be affected to many users, each profile has many modules, each module has many actions.
I'm sending this object from an asmx to a aspx page using a direct service call.
I got an error because of lazy loading ... so I disabled the lazy loading.
this.Configuration.LazyLoadingEnabled = false;
this works fine, I got my user, with the profile null.
To build the menu tree I have to retrieve the profile. I included It :
User user = new User();
using (cduContext db = new cduContext())
{
// get the user
string encryptedPassword = Encryption.Encrypt(password);
user = (from u in db.Users
where u.UserName.Equals(login) &&
u.Password.Equals(encryptedPassword)
select u).FirstOrDefault();
// Include the users profile
user = db.Users.Include("Profile").FirstOrDefault();
}
return user;
I got this error in the javascript call function :
A circular reference was detected while serializing an object of type 'CDU.Entities.Models.User'.
When I made a quick watch on the user object, in asmx ( before sending it ) , I found, that the profile has included the list of the users who had this pofile, each user has his profile loaded ... etc
Any idea please ?
Note, your code should look like this:
using (cduContext db = new cduContext())
{
// get the user
string encryptedPassword = Encryption.Encrypt(password);
var user = from u in db.Users
where u.UserName.Equals(login) &&
u.Password.Equals(encryptedPassword)
select u;
// Include the users profile
return user.Include("Profile").FirstOrDefault();
}
In your code, you were throwing away the first query by overwriting it with the second. And there was no valid reason to create a blank user.
To address your problem, you're going to have make a decision on what you don't want to serialize. In your case, you probably don't want to serialize Profile.Users
You don't mention what serializer you're using. I'm assuming you're using the DataContract serializer?
EDIT:
You would mark your Profile.Users object with the [IgnoreDataMember] Attribute.
Related
so I already finished all of the actual app for this. I just need to setup the backend. I figured Firebase was the best solution since Parse is no longer a thing. What I wanted was:
Users with profiles - These profiles can be viewed by added friends but only edited (written) to by the actual profile owner.
So I read through the Firebase Docs and still cannot really figure out how to do this. They only have 1 Swift application example that does not do anything similar and the one Obj C twitter one, will not even build. All of their docs still have println for Swift which just makes me think it is not updated frequently.
Does anyone have any good examples / tutorials of this? I keep trying to search for things but nothing is as similar enough to what I want. I am more looking on how to setup the db for each user and access it rather actually using Firebase in Swift.
As I wrote in my comment to your question, this answer is based on what we do in a real social app Impether using Swift + Firebase.
Data structure
Let's assume that you want to store the following information for a single user:
email
username
name
followers - number of people who follow a particular user
following - number of people who a particular user follows
avatar_url - url of their avatar
bio - some additional text
Since in Firebase everything is stored a JSON objects, you can store the above structure under node with path like users/$userId, where $userId is Firebase User UID which is created for each registered user if you use simple email/password Firebase authorization.
Firebase email/password authorization is described in their docs:
https://www.firebase.com/docs/ios/guide/user-auth.html
https://www.firebase.com/docs/ios/guide/login/password.html
Notice that there are both Obj-C and Swift snippets. I find Firebase documentation really great as it helped me a lot when I was building our app.
For the purpose of this answer let's assume that we have user with username jack and Firebase User UID equal to jack_uid (in reality this will be a string generated by Firebase).
Then an example data for this user will be store under a path users/jack_uid and can look like this:
{
"email" : "jack#example.com",
"username" : "jack",
"name" : "Jack",
"followers" : 8,
"following" : 11,
"avatar_url" : "http://yourstoragesystem.com/avatars/jack.jpg",
"bio" : "Blogger, YouTuber",
}
Firebase email/password authorization works really well, but let's be honest, if user wants to sign in into the app, it's a lot better for him to use his username than his email he gave while he registering his account.
In order to do that, we decided to store a mapping from usernames to user ids. The idea is that if user inputs his username and password in a login form, we use that mapping to retrieve his user id and then we try to sign him in using his user id and provided password.
The mapping can be stored for example under a path username_to_uid and looks like this:
{
"sample_username_1": "firebase_generated_userid_1",
"sample_username_2": "firebase_generated_userid_2",
...
"jack": "jack_uid",
"sample_username_123": "firebase_generated_userid_123"
}
Then creating a profile may looks like this and it's done as soon as registration of a new account was successful (this snippet is very close to the exact code we use in the production):
func createProfile(uid: String, email: String,
username: String, avatarUrl: String,
successBlock: () -> Void, errorBlock: () -> Void) {
//path to user data node
let userDataPath = "/users/\(uid)"
//path to user's username to uid mapping
let usernameToUidDataPath = "/username_to_uid/\(username)"
//you want to have JSON object representing user data
//and we do use our User Swift structures to do that
//but you can just create a raw JSON object here.
//name, avatarUrl, bio, followers and following are
//initialized with default values
let user = User(uid: uid, username: username, name: "",
avatarUrl: avatarUrl, bio: "",
followers: 0, following: 0)
//this produces a JSON object from User instance
var userData = user.serialize()
//we add email to JSON data, because we don't store
//it directly in our objects
userData["email"] = email
//we use fanoutObject to update both user data
//and username to uid mapping at the same time
//this is very convinient, because either both
//write are successful or in case of any error,
//nothing is written, so you avoid inconsistencies
//in you database. You can read more about that technique
//here: https://www.firebase.com/blog/2015-10-07-how-to-keep-your-data-consistent.html
var fanoutObject = [String:AnyObject]()
fanoutObject[userDataPath] = userData
fanoutObject[usernameToUidDataPath] = uid
let ref = Firebase(url: "https://YOUR-FIREBASE-URL.firebaseio.com/images")
ref.updateChildValues(fanoutObject, withCompletionBlock: {
err, snap in
if err == nil {
//call success call back if there were no errors
successBlock()
} else {
//handle error here
errorBlock()
}
})
}
In addition to this you possibly want to store for each user a list of his followers and a separate list of users he follows. This can be done just by storing user ids at a path like followers/jack_uid, for example it can look like this:
{
"firebase_generated_userid_4": true,
"firebase_generated_userid_14": true
}
This is the way we store sets of values in our app. It very convenient, because it is really user to update it and check if some value is there.
In order to count the number of followers, we put this counter into user's data directly. This makes reading the counter very efficient. However, updating this counter requires using transactional writes and the idea is almost exactly the same as in my answer here: Upvote/Downvote system within Swift via Firebase
Read/write permissions
A part of your question is how to handle permissions to data you store. The good news is that Firebase is exceptionally good here. If you go to your Firebase dashboard there is a tab named Security&Rules and this is the place where you control permissions to your data.
What's great about Firebase rules is that they are declarative, which makes them very easy to use and maintain. However, writing rules in pure JSON is not the best idea since it's quite hard to control them when you want to combine some atomic rules into a bigger rule or your app simple grows and there are more and more different data you store in your Firebase database. Fortunately, Firebase team wrote Bolt, which is a language in which you can write all rules you need very easily.
First of all I recommend to read Firebase docs about Security, especially how does permission to a node influences permission for its children. Then, you can take a look at Bolt here:
https://www.firebase.com/docs/security/bolt/guide.html
https://www.firebase.com/blog/2015-11-09-introducing-the-bolt-compiler.html
https://github.com/firebase/bolt/blob/master/docs/guide.md
For example, we use rules for managing users data similar to this:
//global helpers
isCurrentUser(userId) {
auth != null && auth.uid == userId;
}
isLogged() {
auth != null;
}
//custom types, you can extend them
//if you want to
type UserId extends String;
type Username extends String;
type AvatarUrl extends String;
type Email extends String;
type User {
avatar_url: AvatarUrl,
bio: String,
email: Email,
followers: Number,
following: Number,
name: String,
username: Username,
}
//user data rules
path /users/{$userId} is User {
write() { isCurrentUser($userId) }
read() { isLogged() }
}
//user's followers rules
//rules for users a particular
//user follows are similar
path /followers/{$userId} {
read() { isLogged() }
}
path /followers/{$userId}/{$followerId} is Boolean {
create() { isCurrentUser($followerId) && this == true }
delete() { isCurrentUser($followerId) }
}
//username to uid rules
path /username_to_uid {
read() { true }
}
path /username_to_uid/{$username} is UserId {
create() { isCurrentUser(this) }
}
The bottom line is that you write rules you want using Bolt, then you compile them into JSON using Bolt compiler and then you deploy them into your Firebase, using command line tools or by pasting them into dashboard, but command line is way more efficient. A nice additional feature is that you can test your rules by using tools in Simulator tab in your dashboard.
Summary
For me Firebase is a great tool for implementing a system you want. However, I recommend to start with simple features and learn how to use Firebase in the first place. Implementing social app with functionality like for example Instagram is quite a big challenge, especially if you want to do it right :) It's very tempting to put all functionality there very quickly and Firebase makes it relatively easy to do, but I recommend to be patient here.
In addition, take your time and invest in writing tools. For example, we have two separated Firebase databases, one for production and second for testing, which is really important if you want to write unit and UI tests efficiently.
Also, I recommend building permission rules from the beginning. Adding them later may be tempting, but also quite overwhelming.
Last but not least, follow Firebase blog. They post regularly and you can be up to date with their latest features and updates - this is how I learnt how to use concurrent writes using fanout technique.
I am having trouble extracting UserAccount properties from MembershipReboot in conjunction with Thinktecture IdentityServer. I have both up and running using the Sample repo here: https://github.com/identityserver/IdentityServer3.MembershipReboot
When I request the "openid profile" scope in an Implicit Grant Flow, I am missing a lot of the user account fields such as "given_name, middle_name", etc from the id_token and response from the userinfo endpoint. I understand this is because they need to be assigned in the GetClaimsFromAccount function.
I can see the requestedClaims come into the GetProfileDataAsync() function in the MembershipRebootUserService class and if I hover over the instance of TAccount in GetClaimsFromAccount I can see the Firstname, Lastname, etc properties appearing in the CustomUser dynamic proxy but I can't for the life of me work out how to access them and copy them into the claims collection?
More Info:
I suspect the issue is with this line:
claims.AddRange(userAccountService.MapClaims(account));
It looks like this should be converting the user account properties into claims but I dont get any back.
The way I understand it works is you add an option to your Scope object to return all of the claims for a user. IncludeAllClaimsForUser is the key property.
e.g.
new Scope
{
Enabled = true,
Name = "roles",
Type = ScopeType.Identity,
IncludeAllClaimsForUser = true,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}
}
My request includes the role property as well. This pulled back all the claims for the user from MR for me. My example is with Implicit flow btw.
this is my first stack overflow question, so I'm keeping my fingers crossed!
Scenario:
I have a relationship between contracts and customers, expressed in the model as:
'customer' => array(self::BELONGS_TO, 'Customer', 'customer_id'),
Now, this is fine - I can access my related model in the view without a problem.
What I want, however, is:
to add the ability to add a 'New Customer' button from within the Create Contract page (which is fine)
have it fire up the /views/customer/create form (which is also fine)
but then, once it's created, have it capture the new ID, close the window and return to the Create Contract page with the newly-created Customer ID pre-populated. I cannot for the life of me work out how to do this :(
Any help appreciated.
Gary
One way is this that when your actionSave() saves the customer you can redirect the page to something like
www.website.com/contract/create/CUSTOMER_ID
Now this way you can pass the user ID to the form and have it pre-populated.
With your contract create action being like : -
public function actionCreate($user_id = NULL){
...
$model = new Contract();
if($user_id)
//You can also check here if the user ID is valid or not
$model->user_id = $user_id;
$this->render('create', array(
'model' => $model
));
}
Another way is that you can put the user ID in session and redirect the user to Contract Create page and fetch the user ID there and again pass it to the model as above.
Hope it helps with the issue.
What options/solutions are there for securing data using Entity Framework?
I do not talk about forms login and such here, just assume that the users are authenticated or not.
To illustrate, i attached one of my web api controllers and i wonder if this is the way to do it. The reason why i ask is that i wonder if there are easier ways to do this than writing all this logic to what data to expose in all my controllers.
Also, when looking into a system like breezejs and odata where i can add $expand=TrafficImages to my queries, i would not want users to be able to get my hole database.
So to summarize, what ways are there to securing the data exposed such the users cant download sensible data.
[AllowAnonymous]
public object GetTheoryTests()
{
var identity = ((ClaimsIdentity)((ClaimsPrincipal)HttpContext.Current.User).Identity);
//if (HttpContext.Current.User.Identity.IsAuthenticated)
if (!identity.IsAuthenticated)
return db.TheoryTests.Include(t=>t.TrafficImages).Where(t=>t.PublicAvalible)
.Select(t => new { Id = t.Id, Title = t.Title, Images = t.TrafficImages }).AsEnumerable();
if (User.IsInRole("WebAdmins"))
return db.TheoryTests.AsEnumerable();
var key = identity.GetProvider();
var member = db.Members.Include(m=>m.PayedTheoryTests).SingleOrDefault(m=>m.Identities.Any(
i=>i.identityprovider == key.provider &&
i.nameidentifier == key.id));
if(member!=null)
return db.TheoryTests.Include(t => t.TrafficImages).Where(t => t.PublicAvalible).Select(t => new { Id = t.Id, Title = t.Title, Images = t.TrafficImages }).AsEnumerable();
else
return db.TheoryTests.Include(t => t.TrafficImages).Where(t => t.PublicAvalible)
.Union(member.PayedTheoryTests).Select(t => new { Id = t.Id, Title = t.Title, Images = t.TrafficImages }).AsEnumerable();
}
When thinking about it, what i miss is something like a viewmodel untop of my database depending on the state of the user. Would it be a solution to create two entity frameworks ontop of the same database, one for limited data display and one for more advanced operations?
Meanwhile, until QueryInterceptors arrive, you should take other steps. First, you should look into the techniques for securing a Web API controller or method, a subject beyond the scope of this answer.
Second, w/r/t $expand, you are quite right to be wary of that feature. You may want to inspect which expansions are requested for some controller methods and/or disallow it altogether for others.
Fortunately, this is relatively easy to do. You have access to the request query string. You can detect the presence of "$expand" in that string and analyze it if you want to allow certain expansions and forbid others.
Breeze will add helpers for this in future. You'll have to process the string until then.
You may want to create your own action filter for this purpose if you're up to it.
Great question!. We are currently working on something called QueryInterceptors that will allow you to examine and possibly change or reject the query that was submitted to the server. The "Principal" would be a available context object within each QueryInterceptor method. Please vote for this feature on the "Breeze" website at www.breezejs.com.
In the context of a given Facebook app, suppose User A invited user B to start using it. Once User B accepts to use the app, is there any way to retrieve the ID of User A programmatically (via either PHP/JS SDK) ? This doesn't seem quite documented.
For what it's worth, A/B users are friends, if it's any use.
when user comes following the app request, you can get request id's using
$_GET['request_ids']
then retrieve all the request ids with which you can call graph api to get the corresponding request details like below:
if(isset($_GET['request_ids']))
{
$request_ids = $_GET['request_ids'];
}
$request_ids = explode(",", $request_ids);
foreach($request_ids as $request_id)
{
$request_object = $facebook->api($request_id);
//this $request_object have sender facebook id in the field uid_from
}
If you look here:
http://developers.facebook.com/docs/reference/dialogs/requests/
You can see the object layout. Of note is the data property:
Optional, additional data you may pass for tracking. This will be
stored as part of the request objects created. The maximum length is
255 characters.
In this object you can add your referring UserId and then when the request is claimed, you can then process it on your end.
Hope this helps.