How to best implement custom search on a Membership provider - asp.net-membership

Out of the box, System.Web.Security.Membership implements a couple of search methods:
FindUsersByEmail
FindUsersByName
I'm using the WSAT project from CodePlex to administer my Membership database. The tool implements extra profile properties in a ProfileCommon class.
Let's say I have a property called Firm in the user's profile.
I need to implement a custom search method to search on the Firm property, and I would like to do this all in code. Don't wanna write a stored procedure (since all the profile properties are stored in 1 database column in the WSAT tool).
Something like this obviously isn't the right way to do it, but here it is to just demonstrate accessing the user's profile properties:
private MembershipUserCollection SearchByFirm(string firmName, MembershipUserCollection allRegisteredUsers)
{
MembershipUserCollection searchResults = new MembershipUserCollection();
foreach (MembershipUser user in allRegisteredUsers)
{
ProfileCommon profile = Profile.GetProfile(user.UserName);
if (profile.Firm.ToLowerInvariant().Contains(firmName.ToLowerInvariant()))
{
searchResults.Add(user);
}
}
return searchResults;
}
Can I turn this into some LINQ goodness?

Well can't you just cast it?
IEnumerable<MembershipUser> searchResults = Membership.GetAllUsers().Cast<MembershipUser>();
Hope this helps you guys

Got some help from a colleague who's good with linq. The challenge here is that MembershipUserCollection doesn't implement IEnumerable< T > (!).
List<MembershipUser> searchResults = allUsers.Where(user =>
Profile.GetProfile(user.UserName).Firm.ToLowerInvariant()
.Contains(firmName.ToLowerInvariant())).ToList();
in this case allUsers is a List which I had to populate with the items in the Membership.GetAllUsers() collection.

Just for the record I created this extension method which I think it kinda works:
namespace WebDibaelsaMVC.Utils.MembershipUserCollectionExtensions
{
public static class MembershipUserCollectionExtensions
{
public static IEnumerable<MembershipUser> Where(this MembershipUserCollection userCollection,Func<MembershipUser,bool> func)
{
foreach (MembershipUser membershipUser in userCollection)
{
if (func(membershipUser))
yield return membershipUser;
}
}
}
}
It also converts the MembershipUserCollection to an IEnumerable<MembershipUser> so all other LINQ methods work afterwards.

There is no built in function provided by microsoft. Here is the example of search membership user with UserName and Email Address
Example:
Just Copy below function and implement it - Done...
Public List<MembershipUser> SearchMembershipUser(string strUserName, String strEmail)
{
IEnumerable<MembershipUser> MUser;
if ((!string.IsNullOrEmpty(strUserName) || !string.IsNullOrEmpty(strEmail)))
{
if (!string.IsNullOrEmpty(strUserName) && !string.IsNullOrEmpty(strEmail))
{
MUser = Membership.GetAllUsers().Cast<MembershipUser>()
.Where(x => x.UserName != CurrentUser && x.UserName == strUserName && x.Email == strEmail);
}
else if (!string.IsNullOrEmpty(strUserName))
{
MUser = Membership.GetAllUsers().Cast<MembershipUser>()
.Where(x => x.UserName != CurrentUser && x.UserName == strUserName);
}
else
{
MUser = Membership.GetAllUsers().Cast<MembershipUser>()
.Where(x => x.UserName != CurrentUser && x.Email == strEmail);
}
}
else
{
MUser = Membership.GetAllUsers().Cast<MembershipUser>().Where(x => x.UserName != CurrentUser);
}
return MUser.OrderBy(x => x.UserName).ToList();
}

Related

linq any clause on multiple values

I am trying to create a linq statement to filter otu results using an any clause. My issue is that I dont have a single value to compare against.
In the example below I have a PropertyTaxBill entity that is the parent. Each one has a collection of TaxPropertyAssessmentDetails attached to it.
In this query people can specify that they only want to deal with bills pertaining to a specific class strata so I check to see if any values exist in the classStrata variable. If so then the user selected specific ones. I was trying to do an any clause on the classStrata but instead of giving it a single value to match on I was trying to select all the values in the TaxPropertyAssessmentDetails collection attached to the PropertyTaxBill. Is this possible?
using (var dataContext = contextProvider.GetContext())
{
var query = dataContext.PropertyTaxBills.Where(x => x.Id > 1);
var classStrata = new int[0];
if (classStrata != null && classStrata.Any())
{
query = query.Where(x => classStrata.Any(y => y == x.TaxPropertyAssessmentDetails.SelectMany(z => z.PropertyTaxClassStrataId)));
}
}
You need to use contains so that ef is able to translate to a ef query.
Not sure that i understood your model correctly. Here's a example with a model. Please tell me if i understood incorrect so i can fix it.
public void TestMethod1()
{
IEnumerable<TaxBill> TaxBills = new List<TaxBill>();
var query = TaxBills.Where(x => x.Id > 1);
var classStrata = new int[0];
if (classStrata != null && classStrata.Any())
{
query = query.Where(x => x.AssessmentDetails.Any(ad => ad.TaxClassStrataId.Any(cs => classStrata.Contains(cs))));
}
}
And the entities
public class TaxBill
{
public int Id { get; set; }
public ICollection<AsessmentDetails> AssessmentDetails { get; set; }
}
public class AsessmentDetails
{
public ICollection<int> TaxClassStrataId { get; set; }
}

ASP.Net MVC 3 System.Data.SqlClient.SqlException Timeout expired

I am developing an ASP.Net MVC 3 web application using Entity Framework 4.1. I recently uploaded the application to my test server and I have noticed an error email delivered by ELMAH stating
System.Data.SqlClient.SqlException Timeout expired. The timeout period
elapsed prior to completion of the operation or the server is not
responding.
Below shows some of my code.
Controller
public ActionResult VerifyEmail(int uid, string vid)
{
var userList = _userService.VerifyEmail(uid,vid).ToList();
}
Service
public IList<User> VerifyEmail(int uid, string emailvcode)
{
return _uow.User.Get(u => u.userID == uid && u.emailVerificationCode == emailvcode).ToList();
}
Unit of Work
public class UnitOfWork : IUnitOfWork, IDisposable
{
readonly LocumEntities _context = new LocumEntities();
private GenericRepository<User> _user = null;
public IGenericRepository<User> User
{
get
{
if (_user == null)
{
_user = new GenericRepository<User>(_context);
}
return _user;
}
}
}
Generic Repository
public IList<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
The Timeout error is sometimes happening when the line within the Service method is trying to execute
return _uow.User.Get(u => u.userID == uid && u.emailVerificationCode == emailvcode).ToList();
This error is not happening every time, only occasionally, however, I don't understand why as this query will either return a list of Users, or, a NULL list.
Can anyone spot from my code why this may be happening?
Any feedback would be appreciated as I have no idea why this is happening.
Thanks.
Try increasing the timeout property in the connection string. Also run the SQL Server Profiler to see how much SQL is being generated for your queries, as the query may be returning a large volume of data causing the timeout.

IsUserInRole not working in CSHTML

I have this code, but I don't know why this is not working properly. I have a custom role provider created.
#if (Roles.IsUserInRole(User.Identity.Name, "Manager"))
{
<li>#Html.ActionLink("User Management", "Index", "User")</li>
}
This is the custom code, the rest wasn't modified.
public override bool IsUserInRole(string username, string roleName)
{
UserRoleType usrt = (from usr in db.Users
join usrRole in db.UserRoles on usr.UserID equals usrRole.UserID
where usr.Email == username
select usrRole.UserRoleType).FirstOrDefault();
if (roleName.Split(',').Contains(usrt.UserRoleTypeName))
return true;
return false;
}
This does work when I do this:
UserRoleProvider roleProvider = System.Web.Security.Roles.Provider as UserRoleProvider;
if (roleProvider.IsUserInRole(httpContext.User.Identity.Name, Roles) || String.IsNullOrEmpty(Roles))
return true;
EDIT:
public override string[] GetRolesForUser(string roleName)
{
return db.UserRoleTypes.Select(u => u.UserRoleTypeName).ToArray();
}
Turns out GetRolesForUser was written in correctly and it was pulling all the Users so it authenticated based on ALL users, which means it was in the first place.
Re-read the documentation to get my answer here.
http://msdn.microsoft.com/en-us/library/system.web.security.roleprovider.getrolesforuser.aspx
It appears that User.IsInRole(rolename) uses MembershipProvider.GetRolesForUser(username)
It took me a while to figure that out.

LINQ-To-Sharepoint Multiple content types for a single list

I'm using SPMetal in order to generate entity classes for my sharepoint site and I'm not exactly sure what the best practice is to use when there are multiple content types for a single list. For instance I have a task list that contains 2 content types and I'm defining them via the config file for SPMetal. Here is my definition...
<List Member="Tasks" Name="Tasks">
<ContentType Class="LegalReview" Name="LegalReviewContent"/>
<ContentType Class="Approval" Name="ApprovalContent"/>
</List>
This seems to work pretty well in that the generated objects do inherit from WorkflowTask but the generated type for the data context is a List of WorkflowTask. So when I do a query I get back a WorkflowTask object instead of a LegalReview or Approval object. How do I make it return an object of the correct type?
[Microsoft.SharePoint.Linq.ListAttribute(Name="Tasks")]
public Microsoft.SharePoint.Linq.EntityList<WorkflowTask> Tasks {
get {
return this.GetList<WorkflowTask>("Tasks");
}
}
UPDATE
Thanks for getting back to me. I'm not sure how I recreate the type based on the SPListItem and would appreciate any feedback.
ContractManagementDataContext context = new ContractManagementDataContext(_url);
WorkflowTask task = context.Tasks.FirstOrDefault(t => t.Id ==5);
Approval a = new Approval(task.item);
public partial class Approval{
public Approval(SPListItem item){
//Set all properties here for workflowtask and approval type?
//Wouldn't there be issues since it isn't attached to the datacontext?
}
public String SomeProperty{
get{ //get from list item};
set{ //set to list item};
}
Linq2SharePoint will always return an object of the first common base ContentType for all the ContentTypes in the list. This is not only because a base type of some description must be used to combine the different ContentTypes in code but also it will then only map the fields that should definitely exist on all ContentTypes in the list. It is however possible to get access to the underlying SPListItem returned by L2SP and thus from that determine the ContentType and down cast the item.
As part of a custom repository layer that is generated from T4 templates we have a partial addition to the Item class generated by SPMetal which implements ICustomMapping to get the data not usually available on the L2SP entities. A simplified version is below which just gets the ContentType and ModifiedDate to show the methodology; though the full class we use also maps Modified By, Created Date/By, Attachments, Version, Path etc, the principle is the same for all.
public partial class Item : ICustomMapping
{
private SPListItem _SPListItem;
public SPListItem SPListItem
{
get { return _SPListItem; }
set { _SPListItem = value; }
}
public string ContentTypeId { get; internal set; }
public DateTime Modified { get; internal set; }
public virtual void MapFrom(object listItem)
{
SPListItem item = (SPListItem)listItem;
this.SPListItem = item;
this.ContentTypeId = item.ContentTypeId.ToString();
this.Modified = (DateTime)item["Modified"];
}
public virtual void MapTo(object listItem)
{
SPListItem item = (SPListItem)listItem;
item["Modified"] = this.Modified == DateTime.MinValue ? this.Modified = DateTime.Now : this.Modified;
}
public virtual void Resolve(RefreshMode mode, object originalListItem, object databaseObject)
{
SPListItem originalItem = (SPListItem)originalListItem;
SPListItem databaseItem = (SPListItem)databaseObject;
DateTime originalModifiedValue = (DateTime)originalItem["Modified"];
DateTime dbModifiedValue = (DateTime)databaseItem["Modified"];
string originalContentTypeIdValue = originalItem.ContentTypeId.ToString();
string dbContentTypeIdValue = databaseItem.ContentTypeId.ToString();
switch(mode)
{
case RefreshMode.OverwriteCurrentValues:
this.Modified = dbModifiedValue;
this.ContentTypeId = dbContentTypeIdValue;
break;
case RefreshMode.KeepCurrentValues:
databaseItem["Modified"] = this.Modified;
break;
case RefreshMode.KeepChanges:
if (this.Modified != originalModifiedValue)
{
databaseItem["Modified"] = this.Modified;
}
else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue)
{
this.Modified = dbModifiedValue;
}
if (this.ContentTypeId != originalContentTypeIdValue)
{
throw new InvalidOperationException("You cannot change the ContentTypeId directly");
}
else if (this.ContentTypeId == originalContentTypeIdValue && this.ContentTypeId != dbContentTypeIdValue)
{
this.ContentTypeId = dbContentTypeIdValue;
}
break;
}
}
}
Once you have the ContentType and the underlying SPListItem available on your L2SP entity it is simply a matter of writing a method which returns an instance of the derived ContentType entity from a combination of the values of the base type and the extra data for the missing fields from the SPListItem.
UPDATE: I don't actually have an example converter class as we don't use the above mapping extension to Item in this way. However I could imagine something like this would work:
public static class EntityConverter
{
public static Approval ToApproval(WorkflowTask wft)
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = wft.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = wft.SPListItem["field-name"];
return a;
}
}
Or you could put a method on a partial instance of WorkflowTask to return an Approval object.
public partial class WorkflowTask
{
public Approval ToApproval()
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = this.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = this.SPListItem["field-name"];
return a;
}
public LegalReview ToLegalReview()
{
// Create and return LegalReview as for Approval
}
}
In either situation you would need to determine the method to call to get the derived type from the ContentTypeId property of the WorkflowTask. This is the sort of code I would normally want to generate in one form or another as it will be pretty repetitive but that is a bit off-topic.

LINQ2SQL Entities - Updating only the fields that have changed

I was hoping there was an easier way to do this in my MVC 3 project. In my database, I have a Customer table that is mapped in my application via LINQ2SQL. There is also a partial customer class where I perform updates, look-up etc - which where I have an update method like this:
public static void Update(Customer customer)
{
if (customer == null)
return;
using(var db = new DataBaseContext)
{
var newCustomer = db.Customers.Where(c => c.customer_id = customer.customer_id).SingleOrDefault();
if(newCustomer == null)
return;
newCustomer.first_nm = customer.first_nm;
// ...
// ... Lot's of fields to update
// ...
newCustomer.phone_num = customer.phone_nm;
db.SubmitChanges();
}
}
What I was hoping to find was a less-cumbersome method to update the fields in newCustomer with the corresponding fields in customer that are different.
Any suggestions? Thanks.
I think you can implement IEqualityComparer:
public class Customer
{
public string first_nm { get; set; }
public int phone_num { get; set; }
}
class CustomerComparer : IEqualityComparer<Customer>
{
public bool Equals(Customer x, Customer y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the customer' properties are equal.
return x.first_nm == y.first_nm && x.phone_num == y.phone_num ;
}
}
and do it as follows:
if (newCustomer != customer)
{
myDbContext.Customers.Attach(customer,true); // true means modified.
}
Or implement ICloneable and set newCustomer to customer.Clone(). then there's no need to attach customer since newCustomer is already attached.
in EF(4.1), I think You just have to attach the entity as modified:
myDbContext.Customers.AttachAsModified(customer, this.ChangeSet.GetOriginal(customer), myContext);
UPDATE:
Well, it seems like L2S needs original values of the entity. In reply to your comment, you have a couple choices: Using a timestamp column, returning a subset of entities, or having the original entity in your hand. In your scenario, you have the original entity already:
// This is your original entity
var newCustomer = db.Customers.Where(c => c.customer_id = customer.customer_id).SingleOrDefault();
So you will most probably can do:
if (customer != newCustomer)
{
myDbContext.Customers.Attach(customer, newCustomer);
}
Note: I'd rename newCustomer to originalCustomer if I were you since it's more related to the entity's state.
The problem with this approach is that you have an extra trip to database to get your original customer (newCustomer in your code). Take a look at here, here and definitely here to see how you can use TimeStamp columns to prevent the extra database trip.

Resources