Generic function in VB.net - asp.net

I have 2 different user account type and they both are stored in their respective tables (Members in Member table and Admin in Administrator table). Now i want to create a common function to access user info for any type of user, so i was looking a for generic function but i am stuck with returning respective class, I have create 2 class MemberInfo for normal users and AdminInfo for Admin usersNow if the generic class passed to this function is MemberInfo than it should process normal user details and return MemberInfo class, and if it's admin users, then it should return AdminInfo class.
Here is something what i have tried but unable to achieve my goal.
Public Function GetAllMembers(Of T)(ByVal accountType As AccountType) As List(Of T)
Dim T_ReturnValue As List(Of T)
Dim returnType As Type = GetType(T)
If returnType Is GetType(MemberInfo) Then
Dim _list As New List(Of MemberInfo)
With New OleDbDataAdapter("SELECT ACCOUNT_NO, COUNTRY FROM Member", Globals.DatabaseConnection)
Dim dt As New DataTable
.Fill(dt)
For Each row As DataRow In dt.Rows
Dim memberInfo As New MemberInfo
memberInfo.AccountNo = row("Account_No").ToString
memberInfo.Country = row("Country").ToString
_list.Add(memberInfo)
Next
End With
Return DirectCast(_list, List(Of T))
End If
End Function
Can anyone help me how i can return respective class, for now i wanted to return memberinfo class only.

Two ways:
You can have two overloaded functions that return different classes.
You can declare the function as Object, and return either class.

You can follow these steps.
Create an abstract class say "User" . And then Member and Admin has to extend that base class user. Assuming, both has same set of properties and that is why you have started using T to make it generic. But as you have said both has different DB table store.
If you different methods defined for Member and Admin, you can segregate them by using interface. Say Member can Send Friend request, so you can have an interface ( Say ISendRequest), that will have Send method definition only. And if Admin can Add new member ,then you can have interface say IAddMember, and Admin will implement IAddMember , Member will implement, ISendRequest.
KEY point Now, define an interface say IGetAllUser with method GetAllUser and User class has to implement that, but it will have abstract method GetAllUser. So point here is you have to have to write this one GetAllMembers, instead each derived class will have method to get corresponding List .
Sample code snippet. This can even accommodate the scenario if both Member and Admin has different properties.
But if you have same properties, then you can define a function in Base class, that takes Datatable and just sets required properties, as both member and admin has same properties. So the sole purpose of GetAllUsers implemented in Member and Admin class is to pass required table name to Data Access layer and get DataTable and pass that to function defined in base class to set required properties and build List of User.
public interface IGetAllUsers
{
List<User> GetAllUsers();
}
abstract class User : IGetAllUsers
{
public abstract List<User> GetAllUsers();
}
class Member : User
{
public override List<Member> GetAllUsers()
{
// Assuming there is data access layer, to get details
}
}
class Admin : User
{
public override List<Admin> GetAllUsers()
{
// Get all admin
}
}

Right. Before addressing your specific question, I want to start at the lower level.
In theory, an admin is a user, so at database level this should rather be implemented so that there is a [Users] table that stores all kinds of users including admins. Then you should add another table called [Admins] which links to the [Users] table through an FK and stores all additional fields that relate to admins only. This is called ISA / inheritance relation in RDBMS theory.
At application level, this will translate to two business classes, one for [User] and one for [Admin], where [Admin] will inherit from [User] class. You can then write a function that returns a [User] object. Since [Admin] inherits from [User], polymorphism will allow you to return [Admin] object from the same function. Then your caller can confirm the returned object type either through type checking, or you can store a boolean field in [Users] table called IsAdmin that will be true for administrators.

Related

EventAggregator - Get List of Subscribers

Using EventAggregator with Unity and PRISM, is there a way to get the list of subscribers to a specific event?
I know that some people will say that "Why do you want to know this, the whole point of using an EventAggregator is so that we don't care who or how many subscribers".
This is purely an exercise that I want to carry out it is not for any specific purpose.
EventAggregator must store a list of subscribers is there a way to expose this list?
Yes, the subscriber information is contained within the EventAggregator object graph. Unfortunately (for your request), this information is stored within private fields.
Events are stored in a private Dictionary<Type, EventBase> events. The subscriptions are stored within the event itself (in EventBase) as a
private readonly List<IEventSubscription> _subscriptions = new List<IEventSubscription>();
One option to retrieve the subscription information is to use reflection to access the private member variables (assuming reflection permission exists).
If you can modify the events then another option is to expose this information via the specific PubSub<EventBase> since EventBase allows access to subscriptions for subclasses via the protected ICollection<IEventSubscription> Subscriptions property. For example:
public class MyEvent : PubSubEvent<MyEventData>
{
public new ICollection<IEventSubscription> Subscriptions => base.Subscriptions;
}
Then you can query the event:
var myEvent = eventAggregator.GetEvent<MyEvent>();
var sub = (EventSubscription<MyEventData>) myEvent.Subscriptions.FirstOrDefault();
MethodInfo method = sub.Action.Method;
object target = sub.Action.Target;
If you don't need the specific EventSubscription<T> data (e.g. just want to know subscription counts) then you could avoid the specific cast and use the IEventSubscription interface.

How to manage multiple connections for different users

i am working on a CMS solutions for real estate agencies.
so different users/groups will use the same tool.
i created 1 asp.net membership Database where i manage ALL users.
The users are grouped in different roles.( 1 role = 1 agency office)
Then - for every group i have another Database. In this database i manage the real estates and customers of the given office. (These Databases have the same structure.)
Currently i am using the "custom ASP.NET Profile class" where i store the connectionsstring for the specific database. I create this custom profile if the user logs in.
Now i have the problem, if an anonymous user is visiting the page ( there is a public section ) i get connectionstring errors cause there is no "custom profile" where my functions can read the connectionstring
My Custom Profile Class looks like:
Public Class UserProfile
Inherits ProfileBase
Public Shared Function GetUserProfile(username As String) As UserProfile
Return TryCast(Create(username), UserProfile)
End Function
Public Shared Function GetUserProfile() As UserProfile
Return TryCast(Create(Membership.GetUser().UserName), UserProfile)
End Function
<SettingsAllowAnonymous(False)> _
Public Property role() As String
Get
Return TryCast(MyBase.Item("role"), String)
End Get
Set(value As String)
MyBase.Item("role") = value
End Set
End Property
<SettingsAllowAnonymous(False)> _
Public Property UsersCustomConnectionString() As String
Get
Return TryCast(MyBase.Item("UsersCustomConnectionString"), String)
End Get
Set(value As String)
MyBase.Item("UsersCustomConnectionString") = value
End Set
End Property
End Class
Then i can read my connection string like
Dim currentprofile As UserProfile = UserProfile.GetUserProfile()
Dim strcon As String = currentprofile.UsersCustomConnectionString
How could i solve this issue ?
Or should i use another way to solve the "many connection strings" issue ? if yes, how ? (i think session varaiables won't work)
Thanks in advance
This is what we do: put in web.config an entry for each connection string in the
<appSettings>
section like this:
<add key="connection_string_key" value="YourDBServerConnectionString"/>
Then you read the value from your db access class like this:
System.Configuration.ConfigurationManager.AppSettings[connection_string_key]
And if you want to change them dynamically make some factory class where you read them all and return the right connection string based on the role of the current user or if they are logged in or not.

Structuring Class with constructor

I have a Class with a Constructor. My constructor takses all the required parameter, then I use the parameters to return another class.
Public Class SearchResults()
private id as int
Sub New(id) ' Constructor
getResults(id)
End Sub
Public Function getResults(byval id as int) as List(of Products)
........
return list (of products)
End Function
End
Then in my page I want to get all the productts.
Dim s = new SearchResults( 1 )
Dim p as list(of Products) = s.getResults()
----now I can do for Each on this
This works for me, but I do have a feeling there has to be a better way of doing it, I want to stick to the best standards. do you guys think, this is the best approach or it could be improved? My designers will be utilizing this class within their projects...so i would love to make it as simple as possible for them.
or maybe how to create an Collection of a Class...for example Class Product and its collection Class Products, Where Products is the Collection of Project Class.
There are three ways to do what you want:
1) You can load the results and store them in the object on the constructor
2) You can store the ID in the object and call the function to get the results when needed
3) You can make the function static and pass in the ID as well as the collection (or resource needed to get the collection) and not use an object at all.
Depending on what you need, most likely either 1 or 3 are going to be best. If you plan on reusing the object for other methods than just the one function, then option 1 is the best, but if you just need the 1 function, go with option 3 like this:
Public Class SearchResults
Public Static Function getResults(ByVal id As int) As List(Of Products)
'........
return list (of products)
End Function
End Class
You could make the getResults method static possibly and cut out having to create a class instance to call it.
I personally would declare the getResults method as Shared so that you don't have to create a SearchResults object just to access that method. This would also allow you to call the method again with another ID without having to create another object.

C# CF2.0 - System.Activator and Internal classes

I've got a data provider that contains a collection of entities. I only want to be able to create a new entity through the data provider.
I.e, to create a new record I need to use:
Entity entity = Provider.AddNew();
enity.set_Properties... etc
My issue is that if I set my entities to Internal, System.Activator cannot create an Instance of them. Each of my Data Providers uses a Base class with the generic type of the entity passed through.
So at the moment my AddNew() method contains the following:
public T AddNew()
{
T added = Activator.CreateInstance<T>();
this.Collection.Add(added);
return added;
}
It's obviously not the end of the world if I can instantiate a new entity manually outside of the Data Provider namespaces, but it seems pointless considering there's no way to ever save them, so why give the option to do so?
EDIT: Forgot to mention that all my providers, entities, etc are in the same namespace.
Don't use the Activator, which relies on a public constructor. Instead use reflection to find the parameterless constructor and then call it. Something along these lines:
Type t = typeof(MyType);
var parameterlessCtor = (from c in t.GetConstructors(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
where c.GetParameters().Length == 0
select c).FirstOrDefault;
if(parameterlessCtor != null) instance = parameterlessCtor.Invoke(null);

Extend System.Web.HttpContext.User

I would like to extend the System.Web.HttpContext.User object (ASP.NET/VB.NET) so that it contains other fields besides just Name. I understand I can create an object that inherits the System.Security.Principal.GenericPrincipal class, but how do I store that in the Current.User object in a usable fashion. ie, I can do something like Current.User.UserID.
So far to achieve this I've created a kludgy workaround by using | delimited strings in the User.Name property and then splitting them, but it's getting kind of ridiculous.
Any suggestions?
Thanks!
EDIT: I have tried the following to no avail:
Imports System.Security.Principal
Public Class CurrentUser : Inherits GenericPrincipal
Private _totalpoints As Integer
Private _sentencecount As Integer
Private _probationuntil As DateTime
Public ReadOnly Property TotalPoints() As Integer
Get
Return _totalpoints
End Get
End Property
Public ReadOnly Property SentenceCount() As Integer
Get
Return _sentencecount
End Get
End Property
Public ReadOnly Property ProbationUntil() As DateTime
Get
Return _probationuntil
End Get
End Property
Public Sub New(ByVal principle As IIdentity, ByVal roles() As String, _
ByVal points As Integer, ByVal sentences As Integer, ByVal probationTil As DateTime)
MyBase.New(principle, roles)
_totalpoints = points
_sentencecount = sentences
_probationuntil = FixDBNull(probationTil)
End Sub
End Class
setting the object in my Global.asax Application_AuthenticateRequest function like so:
HttpContext.Current.User = New CurrentUser(User, userRoles, _
points, sentenceCount, probationUntil)
with a direct cast wherever the object is needed like so:
Dim thisUser As CurrentUser = DirectCast(Current.User, CurrentUser)
i also tried CType and it didn't work... my error is
[InvalidCastException: Unable to cast object of type 'System.Security.Principal.GenericPrincipal' to type 'myProject.CurrentUser'.]
i'm losing my mind here ... :( thanks guys...
anyone?
You can create your own Principal class with the required properties, that inherits from a Generic Principal, and then set the User property of your Current Context to be the a user of that type.
The example below is for ASP.Net MVC but a similar approach could be used with webforms.
You can do this in the PostAuthenticateRequest after a user is authenticated (in the Global.asax)
private void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
SomePrincipal newUser = new SomePrincipal(User.Identity, tmpRoles);
senderRef.Context.User = newUser;
System.Threading.Thread.CurrentPrincipal = newUser;
}
You could then add a property or method in a base class of your page (or controller) for example that to wrap and type the Context.User principal to your Principal type and make sure you call it rather than calling the one on the HttpContext.
There are probably other solutions too!
Would this approach work for you? It looks a little involved but it really doesn't take too long to setup:
Create a 'base' class of your own, and have your pages inherit from that. For example, create a base class called 'BasePage' which inherits from System.Web.UI.Page.
Have your ASP.net pages inherit from your new BasePage class.
In the BasePage class, you can have a public property which contains the extra fields you want to store for your user (eg. BasePage.FirstName, BasePage.LastName). Better still, create a User object containing the extra fields, and expose that via BasePage, eg. "BasePage.Customer". This keeps things tidy if you plan to extend BasePage later.
You can then override the OnInit() of the base class to check for HTTPContext.Current.User.Name property, and fetch the necessary info from your DB to initialise your custom properties.
You can modify the code so that it won't need to hit the database each time the page is refreshed by using ControlState to check whether the custom fields have values before populating them again from the database.
Hope this helps...
Richard.

Resources