Load ProfileBase without HTTP Context - asp.net

I'm in the process of converting user profile data that was serialized in the classic ASP.Net Membership Provider for use in SimpleMembership. I cannot figure out how to get the ProfileBase object for every user in the system.
If a specific user is logged in, I can do something like:
MyModel myModel =
(MyModel)HttpContext.Current.Profile.GetPropertyValue("MyKey");
where MyKey refers to a profile key established in web.config like this:
<add name="MyModel" type="MyNS.MyModel" serializeAs="Binary" />
However, without the benefit of an HTTP context (I'm trying to do this for all users in the system, not a logged-in user) I can't figure out how to load the profile and ultimately an instance of MyModel for each user in the system.
I have tried:
ProfileInfoCollection profiles =
ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All);
foreach (var profile in profiles)
{
var pi = (ProfileBase)profile;
// OOPS! Unfortunately GetAllProfiles returns
// ProfileInfo and not ProfileCommon or ProfileBase
}
and
MembershipUserCollection existingUsers = Membership.GetAllUsers();
foreach (MembershipUser mu in existingUsers)
{
mu. // OOPS! No link to the profile from the user...
}
How can I retrieve the ProfileCommon or ProfileBase instance for each profile in the system, and thus ultimately the MyModel associated with each user?

Since I could not find an answer to this question, I opted to just read the profile data directly from SQL.
It turns out that the format is straightforward. In aspnet_Profile:
PropertyNames uses a format NameOfProperty:TypeFlag:Offset:Length (repeat for all properties).
FlagType is "S" for string or "B" for binary
Offset is the offset in the appropriate data field
Length is the length of data in the appropriate data field
PropertyValuesString holds all string properties concatenated without a delimiter.
PropertyValuesBinary holds all binary properties concatenated without a delimiter.
BinaryFormatter is used to serialize binary (non-string) properties
Here's a little code I wrote to parse the data:
private class Migrate_PropNames
{
public string Name { get; set; }
public bool IsString { get; set; }
public int Offset { get; set; }
public int Length { get; set; }
}
....
Dictionary<string, Migrate_PropNames> propInfo = ParsePropInfo(propertyNames);
// Example string property
string firstName = Migrate_GetString(propInfo["FirstName"], propertyValuesString);
// Example binary property
MyType myType =
Migrate_GetBinary<MyType>(propInfo["MyTypeKey"], propertyValuesBinary));
private T Migrate_GetBinary<T>(Migrate_PropNames propNames, byte[] propertyValuesBinary)
{
byte[] data = new byte[propNames.Length];
Array.Copy(propertyValuesBinary, propNames.Offset, data, 0, propNames.Length);
var fmt = new BinaryFormatter();
using (var ms = new MemoryStream(data))
{
T original = (T)fmt.Deserialize(ms);
return original;
}
}
private string Migrate_GetString(Migrate_PropNames propNames, string propertyNames)
{
return propertyNames.Substring(propNames.Offset, propNames.Length);
}
private Dictionary<string, Migrate_PropNames> ParsePropInfo(string propertyNames)
{
Dictionary<string, Migrate_PropNames> result = new Dictionary<string,Migrate_PropNames>();
string[] parts = propertyNames.Split(new string[] { ":"}, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length; i += 4)
{
Migrate_PropNames pn = new Migrate_PropNames();
pn.Name = parts[i];
pn.IsString = (parts[i + 1] == "S");
pn.Offset = int.Parse(parts[i + 2]);
pn.Length = int.Parse(parts[i + 3]);
result.Add(pn.Name, pn);
}
return result;
}
I hope this helps someone. I'll gladly accept a different answer that correctly shows how to use the API.

From the ProfileInfo or MemberShipUser object, you should can get a ProfileBase one using ProfileBase.Create(string username).

Related

Old ASP.NET code works on one computer, not on another?

So in my global.asax, I've got the following code:
Inventory.BusinessTier bt = new Inventory.BusinessTier();
string UserLogin = bt.ExtractLogin (Request.ServerVariables ["AUTH_USER"]);
Inventory.User myUser = new Inventory.User (UserLogin);
Session ["User"] = myUser;
It works just fine on one development PC, but using the same version of Visual Studio, it craps out on the third line with this error:
System.TypeInitializationException: 'The type initializer for
'Inventory.DataTier' threw an exception.'
Inner Exception
NullReferenceException: Object reference not set to an instance of an
object.
Other than a line adding impersonation in my web.config (it has to be there now), I haven't changed a single thing. Is there a way to get more info on this? I can't even trace it, because if I put a debug line in the User object constructor, it never hits it. I'm at a bit of a loss. Would appreciate any advice.
EDIT to answer questions below:
InventoryUser is a very simple user object that reads the current from the database and stores some basic user info in properties, such as UserID, Role, RoleID, and IsAdmin.
The DataTier class is a class that interacts with the database. It is used in multiple projects, so I'm quite sure it's not the problem. I tried to paste in the code anyway, but it exceeded the limit for a post.
I'm reasonably sure the problem is related to the user class. It's short, so I can paste it in here:
using System;
using System.Data;
// This is the user business object. It contains information pertaining to the current user of the application. Notably, it
// contains the department ID, which determines what inventory items the user will see when using the application. Only
// specified employees with admin access can see all items for all departments, and that is determined by a specific department ID.
namespace Inventory {
public class User {
private Guid _UserID;
private Guid _RoleID;
private Guid _UserDepartmentID;
private string _UserRole = "";
private string _UserName = "";
private bool _IsAuthorizedUser = false;
private bool _IsAdmin = false;
// Attribute declarations
public Guid UserID {
get {
return _UserID;
}
set {
_UserID = value;
}
}
public string UserRole {
get {
return _UserRole;
}
set {
_UserRole = value;
}
}
public Guid RoleID {
get {
return _RoleID;
}
set {
_RoleID = value;
}
}
public string UserName {
get {
return _UserName;
}
set {
_UserName = value;
}
}
public Guid UserDepartmentID {
get {
return _UserDepartmentID;
}
set {
_UserDepartmentID = value;
}
}
public bool IsAdmin {
get {
return _IsAdmin;
}
set {
_IsAdmin = value;
}
}
public bool IsAuthorizedUser {
get {
return _IsAuthorizedUser;
}
set {
_IsAuthorizedUser = value;
}
}
// -----------------
// - Constructor -
// -----------------
public User (string UserLogin) {
string ShortUserLogin = ExtractLogin (UserLogin);
GetUser (ShortUserLogin);
}
// ------------------
// - ExtractLogin -
// ------------------
public string ExtractLogin (string Login) {
// The domain and "\" symbol must be removed from the string, leaving only the user name.
int pos = Login.IndexOf (#"\");
return Login.Substring (pos + 1, Login.Length - pos - 1);
}
// -------------
// - GetUser -
// -------------
// This method is called to fill the user object based on the user's login. It ultimately gets authorized user data
// from the user table.
public void GetUser (string UserName) {
DataTier dt1 = new DataTier();
DataTable dt = dt1.GetUserInfo (UserName);
int RecordCount = dt.Rows.Count;
switch (RecordCount) {
case 1: // There is one user name match, as there should be. This is the likely situation.
DataRow dr = dt.Rows[0];
UserID = (Guid)dr ["UserID"];
UserRole = (string)dr ["UserRole"];
RoleID = (Guid)dr ["RoleID"];
this.UserName = UserName;
UserDepartmentID = (Guid)dr ["DepartmentID"];
IsAdmin = (bool)dr ["IsAdmin"];
IsAuthorizedUser = true;
break;
case 0: // There are no user name matches (unauthorized use).
IsAdmin = false;
IsAuthorizedUser = false;
break;
default: // There are multiple user name matches (problem!).
IsAdmin = false;
IsAuthorizedUser = false;
break;
}
}
}
}

How to add data to associative table in asp.net core

I am new to asp.net core. I am building a web application for book management. I have a table called Author and books. Being a many to many relationships I made an associative entity that consists of the bookId and authorId. When I try to create I am able to create author and book. I successfully added the author and book to the database.
My author class looks like this
public class Author
{
private int _ID
private string _Name;
public string ID {
get { return _ID; }
set { _ID = value; }
public string Name {
get { return _Name; }
set { _Name = value; }
}
My book class is
public class Author
{
private int _ID
private string _Name;
private string _Title;
public string ID {
get { return _ID; }
set { _ID = value; }
}
public string Title {
get { return _Name; }
set { _Name = value; }
}
public string Name {
get { return _Name; }
set { _Name = value; }
}
I have a data access called db.cs to help to create the book and author in database.
public static int AddAuthor(Author A)
{
int renum = -1;
SqlConnection conn = null;
conn = new SqlConnection(ConnectionString);
conn.Open();
SqlCommand comm = new SqlCommand("sproc_AuthorAdd", conn);
comm.CommandType = System.Data.CommandType.StoredProcedure;
comm.Parameters.AddWithValue("#Name", A.Name);
comm.Parameters.AddWithValue("#Title", a.Title);
SqlParameter output = new SqlParameter();
output.ParameterName = "#AuthorID";
output.DbType = System.Data.DbType.Int32;
output.Direction = System.Data.ParameterDirection.Output;
comm.Parameters.Add(output);
int affect = comm.ExecuteNonQuery();
renum = affect;
c.ID = (int)output.Value;
I have done the same for books as well. I want to fill out the association table as well when the user filled out a book and author using their ID. I tried to do various things like using a cookie to pass data. But I cannot store data. Any kind of help is appreciated. Thanks in advance.
I'm not really sure I understand your last code snippet, but if you're having issues managing your many-to-many relationship between Books and Authors, have you considered just using Entity Framework Core?
Instead of writing a bunch of code that accesses your database, you just create models of your tables (similar to the classes you have defined above), and it handles the many-to-many relationship for you. The code to query for Authors and/or Books could then look as simple as:
using (var db = new dbContext())
{
var books = db.Books
.Where(b => b.ID > 1234)
.OrderBy(b => b.Title)
.ToList();
}
And creating a new Book or Author would be similarly simple:
using (var db = new dbContext())
{
var book = new Book { ID = 1234, Title = "Some Title", Name = "Some Name" };
db.Books.Add(book);
db.SaveChanges();
}
You might have to reimplement a bunch of things to take advantage of Entity Framework Core in your app, but it sounds like it would save you time in the long run.

Save and Restore an object to database

Lets say i have an object with this format:
public class ObjectClassSample
{
public string product { set; get; }
public string Description { set; get; }
public int Price { set; get; }
}
Im trying to same this object inside a string field in a record in my database. is it possible to this without converting this to JSON, as i was thinking what is the best way to save and restore this.
One way or another you have to convert that object to a string, I'm unsure why you don't want to use JSON, but to do it without converting to JSON, you could make your own error prone format.
Here is an example of just converting the object to a string, separating each property by a comma.
Some Extension Methods
public static class ObjectSampleExtensions
{
public static ObjectClassSample ToObjectClassSample(this string s)
{
var parts = s.Split(new [] { ','});
return new ObjectClassSample
{
product = parts[0],
Description = parts[1],
Price = int.Parse(parts[2])
};
}
public static string ConvertToString(this ObjectClassSample objectToConvertToString)
{
const string delimiter = ",";
var sb = new StringBuilder();
sb.Append(objectToConvertToString.product);
sb.Append(delimiter);
sb.Append(objectToConvertToString.Description);
sb.Append(delimiter);
sb.Append(objectToConvertToString.Price);
return sb.ToString();
}
}
Then Usage
void Main()
{
var obj = new ObjectClassSample
{
Description = "this is the description",
Price = 3,
product = "my product"
};
var s = obj.ConvertToString();
//you can now save s to the database
Db.Save(s);
//later on pretend you read 's' back from the database
s = Db.ReadAnItem();
var objectFromDb = s.ToObjectClassSample();
}
So yeah, you can serialize the data anyway you want, but I would use a common format: json, xml, csv, whatever.
I wouldn't recommend using the code above, that was just an example to show you can basically do whatever you want to convert it to a string, so long as you can convert it back. Using a json parser would be much easier though.
An example with ServiceStack.Text would look like this
var objToSerialize = new ObjectClassSample(); //fill this with data
string myObjectAsString = objToSerialize.ToJson();
//reading it back from the database
ObjectClassSample myObj = myObjectAsString.FromJson<ObjectClassSample>();
I'm sure newstonsoft.json is similar.
As you can see...much prettier.

Why is my DataContractJsonSerializer failing on the call to ReadObject()?

I am trying to deserialize some json received from a Web API method being called from a .NET 3.5 Winforms app based on this code: http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
The json is being returned, but upon deserialization, it is failing to grab root and therefore growling:
Here is the client code in question:
try
{
var client = new RestClient();
client.BaseUrl = "http://localhost:48614/"; // <-- this works
var request = new RestRequest();
request.Resource = "api/departments/"; // can replace this with other data, such as redemptions, etc.
RestResponse response = client.Execute(request) as RestResponse;
if ((response.StatusCode == HttpStatusCode.OK) && (response.ResponseStatus == ResponseStatus.Completed)) // Both are probably not necessary
{
MessageBox.Show(string.Format("Content is {0}", response.Content));
// from http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
MemoryStream deptStream = new MemoryStream();
DataContractJsonSerializer cereal = new DataContractJsonSerializer(typeof(Department));
deptStream.Position = 0;
Department dept = (Department)cereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
}
else
{
MessageBox.Show(string.Format("Status code is {0} ({1}); response status is {2}",
response.StatusCode, response.StatusDescription, response.ResponseStatus));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The response.Content line is doing just fine, displaying the json data in the dialog.
The Department data is defined this way in the .NET 4 ASP.NET / Web API app:
namespace DuckbilledPlatypusServerWebAPI.Models
{
public class Department
{
[Key]
public int Id { get; set; }
[Required]
public string AccountId { get; set; }
[Required]
public string DeptName { get; set; }
}
}
...and this way in the .NET 3.5 Winforms app that receives the data:
[DataContract]
public class Department
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string AccountId { get; set; }
[DataMember]
public string DeptName { get; set; }
}
So what does it yet need to work? How am I to supply it with a 'root' element, as it seems to be demanding?
UPDATE
Badri's answer solves the err msg, but I'm still not getting any data to work with the DataContractJsonSerializer, or I'm accessing it wrong. Here is my code now:
MessageBox.Show(string.Format("Content is {0}", response.Content));
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
DataContractJsonSerializer jasonCereal = new DataContractJsonSerializer(typeof(Department));
Department dept = (Department)jasonCereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
...and, although the first message box shows the jsonarray:
...the second one says accountId and deptName are empty strings. In what way am I maltrreating DataContractJsonSerializer?
deptStream is newed up but where do you load the JSON response returned into the MemoryStream, before the deserialization. You should do something like this.
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
// Deserialize now
UPDATE
Your JSON corresponds to a list of Department objects not a single Department object. Try something like this.
var jasonCereal = new DataContractJsonSerializer(typeof(List<Department>));
var depts = (List<Department>)jasonCereal.ReadObject(deptStream);
foreach(var dept in depts)
MessageBox.Show(
String.Format("accountId is {0}, deptName is {1}",
dept.AccountId, dept.DeptName));

What Good way to keep some different data in Cookies in asp.net?

I want to keep some different data in one cookie file and write this class, and want to know - is this good? For example - user JS enable.When user open his first page on my site, i write to session his GMT time and write with this manager JS state. (GMT time is ajax request with js). And i want to keep some data in this cookie (up to 10 values). Have any advices or tips?
/// <summary>
/// CookiesSettings
/// </summary>
internal enum CookieSetting
{
IsJsEnable = 1,
}
internal class CookieSettingValue
{
public CookieSetting Type { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Cookies to long time of expire
/// </summary>
internal class CookieManager
{
//User Public Settings
private const string CookieValueName = "UPSettings";
private string[] DelimeterValue = new string[1] { "#" };
//cookie daat
private List<CookieSettingValue> _data;
public CookieManager()
{
_data = LoadFromCookies();
}
#region Save and load
/// <summary>
/// Load from cookie string value
/// </summary>
private List<CookieSettingValue> LoadFromCookies()
{
if (!CookieHelper.RequestCookies.Contains(CookieValueName))
return new List<CookieSettingValue>();
_data = new List<CookieSettingValue>();
string data = CookieHelper.RequestCookies[CookieValueName].ToString();
string[] dels = data.Split(DelimeterValue, StringSplitOptions.RemoveEmptyEntries);
foreach (string delValue in dels)
{
int eqIndex = delValue.IndexOf("=");
if (eqIndex == -1)
continue;
int cookieType = ValidationHelper.GetInteger(delValue.Substring(0, eqIndex), 0);
if (!Enum.IsDefined(typeof(CookieSetting), cookieType))
continue;
CookieSettingValue value = new CookieSettingValue();
value.Type = (CookieSetting)cookieType;
value.Value = delValue.Substring(eqIndex + 1, delValue.Length - eqIndex-1);
_data.Add(value);
}
return _data;
}
public void Save()
{
CookieHelper.SetValue(CookieValueName, ToCookie(), DateTime.UtcNow.AddMonths(6));
}
#endregion
#region Get value
public bool Bool(CookieSetting type, bool defaultValue)
{
CookieSettingValue inList = _data.SingleOrDefault(x => x.Type == type);
if (inList == null)
return defaultValue;
return ValidationHelper.GetBoolean(inList.Value, defaultValue);
}
#endregion
#region Set value
public void SetValue(CookieSetting type, int value)
{
CookieSettingValue inList = _data.SingleOrDefault(x => x.Type == type);
if (inList == null)
{
inList = new CookieSettingValue();
inList.Type = type;
inList.Value = value.ToString();
_data.Add(inList);
}
else
{
inList.Value = value.ToString();
}
}
public void SetValue(CookieSetting type, bool value)
{
CookieSettingValue inList = _data.SingleOrDefault(x => x.Type == type);
if (inList == null)
{
inList = new CookieSettingValue();
inList.Type = type;
inList.Value = value.ToString();
_data.Add(inList);
}
else
{
inList.Value = value.ToString();
}
}
#endregion
#region Private methods
private string ToCookie()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < _data.Count; i++)
{
sb.Append((int)_data[i].Type);
sb.Append("=");
sb.Append(_data[i].Value);
sb.Append(DelimeterValue[0]);
}
return sb.ToString();
}
/// <summary>
/// Cookie length in bytes. Max - 4 bytes
/// </summary>
/// <returns></returns>
private int GetLength()
{
return System.Text.Encoding.UTF8.GetByteCount(ToCookie());
}
#endregion
}
P.S. i want to keep many data in one cookies file to compress data and decrease cookies count.
Don't put data into cookies. All cookie data is uploaded from the client on every request to your web site. Even users with good broadband connections often have very limited upload bandwidth, and so storing significant data in cookies can be very bad for perceived performance.
Instead, simply store a value in the cookie that you can use as a lookup to a database table when needed.
Don't put data into cookie. What Joel say is stands and I like to say one more think. Browser some time behave strange if you have a large amount data on your cookie, and you get problems that you do not even imaging where they come from. And this is from my experience.
behave strange:They sow blank white pages, or they can not load the page and you see the cursor wait and wait, or lose the cookie, or you lose data from your cookie and you can not login for example, and other thinks like that.

Resources