locked
Beta 2 - Can we create custom "User Registration" & user "Login" form?

    Question

  • In Beta 2, can we do the followings with an outside Database:

    a) I have all the ASP.Net membership tables included in my current database. Can LS use these set of tables and not creating a new database with membership for LS?

    b) Considering Yes to above question, I need the ability to create my own "User Registration" form to present to user. The form needs to provide the user the different roles available to assign to user. During this process, I also need to store certain info into User's Profile (part of ASP.Net membership). Can we as of Beta 2 control user creation and bypassing LS std. form?

    c) Similar question, regarding custom Login form that will allow us to have more control over the login event.

    If the answer is Yes to all above (or at least (a) & (b)), any docs or samples would be appreciated.

    Thanks!


    ..Ben
    Tuesday, March 15, 2011 11:58 PM

Answers

  • The next changes are required ONLY if you want to share roles and users across multiple applications

    · Your apps need to use the same ApplicationName property in the provider string

    · You need to define a machine key – this must be defined the same in all applications that are sharing users

    *** It should be noted that roles have to mapped to permissions for each application individually as the permissions exist in each app uniquely (they’re defined in code) – the role to permission mapping will always be stored in the intrinsic store of each application and cannot be changed.

    <machineKey validationKey="C50B3C89CB21F4F1422FF158A5B42D0E8DB8CB5CDA1742572A487D9401E3400267682B202B746511891C1BAF47F8D25C07F6C39A104696DB51F17C529AD3CABE"

    decryptionKey="8A9BE8FD67AF6979E7D20198CFEA50DD3D3799C77AF2B72F"

    validation="ABC" />

    <membership defaultProvider="AspNetMembershipProvider">

    <providers>

    <clear />

    <add name="AspNetMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="_AuthData" applicationName="Application8" requiresUniqueEmail="false" requiresQuestionAndAnswer="false" />

    </providers>

    </membership>

    <roleManager enabled="True" defaultProvider="AspNetRoleProvider">

    <providers>

    <clear />

    <add name="AspNetRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="_AuthData" applicationName="Application8" />

    </providers>

    </roleManager>

    <profile enabled="True" defaultProvider="AspNetProfileProvider">

    <providers>

    <clear />

    <add name="AspNetProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="_AuthData" applicationName="Application8" />

    </providers>

    This change is required to allow moving between two applications without having to login again (For Forms auth only) – provided the user has permissions in both applications:

    · The cookie name must be the same for both applications

    <authentication mode="Forms">

    <forms name="Application8" />

    </authentication>

    After you’ve made the necessary changes to your web.config, then you will need to run the Microsoft.LightSwitch.SecurityAdmin.exe utility which is available in your LightSwitch install directory. This utility is used to create a new Auth administrator that has the SecurityAdministrator privilege which enables the managing of roles and users. This is done for you at deployment time (provided you chose the option) but since you’ve changed your Authentication database location, the administrator needs to be created in the new database location. You can run the utility from any location that has access to your authentication database. The call should look something like this.

    …\Program Files\Microsoft Visual Studio 10.0\LightSwitch\1.0\Tools\Microsoft.LightSwitch.SecurityAdmin.exe/createadmin /user:MyAdminUser /password:strong#Password /fullname:Admin /config:c:\....\web.config

    Now on to the question of creating your own administration screen – you certainly can do that. The API’s are available that allow you to create roles and users and map them ass necessary. Creating your own screens will require you to use custom controls for things like not showing passwords in clear text and such if you’re using forms authentication. You would also need to use custom controls if you want to do things like display the available permissions or roles in a drop-down list. It’s all doable but will be a bit of work since the access control entities are not exposed. You can find the API’s you’re interested in DataWorkspace.SecurityData.

    I’ve pulled together just a real simple example of a custom admin screen to create roles and users. This example is just to show you the API – it’s not an example of a robust experience at all (it is a working sample though). This implementation takes the basic data for roles and users and then also adds e-mail and phone number which is stored in a table in the intrinsic store. Hopefully this will help get you started:

    using System;

    using System.Linq;

    using System.IO;

    using System.IO.IsolatedStorage;

    using System.Collections.Generic;

    using Microsoft.LightSwitch;

    using Microsoft.LightSwitch.Framework.Client;

    using Microsoft.LightSwitch.Presentation;

    using Microsoft.LightSwitch.Presentation.Extensions;

    using Microsoft.LightSwitch.Security;

    namespace LightSwitchApplication

    {

    public partial class CustAdmin

    {

    partial void CustAdmin_Saving(ref bool handled)

    {

    Role newRole = null;

    UserRegistration newUser = null;

    RolePermission newRolePermission = null;

    Permission newUserPerm = null;

    this.RoleInput = this.RoleInput.ToLower();

    this.UserNameInput = this.UserNameInput.ToLower();

    //check if the user exists - if one exists throw an error

    IDataServiceQueryable<UserRegistration> userquery = from myuser in this.DataWorkspace.SecurityData.UserRegistrations

    where myuser.UserName == this.UserNameInput

    select myuser;

    newUser = userquery.SingleOrDefault();

    if (newUser != null)

    throw new InvalidOperationException("The user already exists");

    //get the newUser permission to give to the new role

    //all new users get only this role initially

    //TODO alternate implementation: use a custom control and give a drop-down list of available permissions/roles

    newUserPerm = this.DataWorkspace.SecurityData.Permissions_Single(Permissions.NewUser);

    //check if the role exists - if one exists, use that role

    IDataServiceQueryable<Role> rolequery = from myrole in this.DataWorkspace.SecurityData.Roles

    where myrole.Name == this.RoleInput

    select myrole;

    newRole = rolequery.SingleOrDefault();

    //if no existing role was found, create a new one.

    if (newRole == null)

    {

    newRole = this.DataWorkspace.SecurityData.Roles.AddNew();

    newRole.Name = this.RoleInput;

    //add the permission to the role

    newRolePermission = this.DataWorkspace.SecurityData.RolePermissions.AddNew();

    newRolePermission.Permission = newUserPerm;

    newRolePermission.Role = newRole;

    }

    //only look for existing role permission mapping on existing roles

    else

    {

    //see if there is already a mapping for this role and permission

    IDataServiceQueryable<RolePermission> rolePermissionQuery = from myroleperm in this.DataWorkspace.SecurityData.RolePermissions

    where (myroleperm.PermissionId == Permissions.NewUser && myroleperm.RoleName.ToLower() == this.RoleInput)

    select myroleperm;

    newRolePermission = rolePermissionQuery.SingleOrDefault();

    //the role permission doesn't exist so add it

    }

    //if no rolePermission exists

    if (newRolePermission == null)

    {

    newRolePermission = this.DataWorkspace.SecurityData.RolePermissions.AddNew();

    newRolePermission.Permission = newUserPerm;

    newRolePermission.Role = newRole;

    }

    newUser = this.DataWorkspace.SecurityData.UserRegistrations.AddNew();

    newUser.UserName = this.UserNameInput;

    //TODO alternate implementation: real screen would need a password input box and confirm password logic for Forms auth

    newUser.Password = this.PasswordInput;

    newUser.FullName = this.DisplayNameInput;

    this.DataWorkspace.SecurityData.SaveChanges();

    RoleAssignment newRoleAssign = newUser.RoleAssignments.AddNew();

    newRoleAssign.Role= newRole;

    newRoleAssign.User = newUser;

    this.DataWorkspace.SecurityData.SaveChanges();

    }

    As you are considering alternate ways of working with your access control data you might also like to consider Matt’s approach to accessing this data – http://blogs.msdn.com/b/mthalman/archive/2010/09/20/how-to-reference-security-entities-in-lightswitch.aspx

    Hope this helps!

    Valerie


    Valerie G. Andersen
    • Proposed as answer by Valerie Andersen Thursday, March 17, 2011 8:04 PM
    • Marked as answer by Ben Hayat Thursday, March 17, 2011 9:46 PM
    Thursday, March 17, 2011 8:04 PM

All replies

  • Haven't tried it yet, but I expect (well hope) that we can now configure custom membership and role providers? Would also like to know more about Ben's questions as they relate to RIA services.

    Thanks

    Wednesday, March 16, 2011 12:26 AM
  • Hi Guys,

    It is possible to use ASP.NET user tables and to provide an integrated Login, however this isn't covered in the product docs and I don't have an example. I know that Michael Washington has already got this working with DotNetNuke, and I believe he is planning on putting up an example on his site soon.

    Regards,


    Steve Hoag Microsoft aka the V-Bee
    Wednesday, March 16, 2011 5:34 AM
  • Thanks Steve, we'll keep an eye out for Michael's example.

    Regards
    Wednesday, March 16, 2011 7:48 AM

  • With a LOT of help from the LightSwitch team during the MVP Summit I did get this working in DotNetNuke. I probably wont have an article up for a week because it is complicated due to DotNetNuke.

    However, I know Ben is not using DotNetNuke so the tutorial that I am working on right now should provide the answers he needs. This one should be posted on my site in the next two days.

    However, it is REALLY very simple:

    1) Enable Forms Authentication in your LightSwitch project
    2) Deploy as a 3-tier application to IIS
    3) Make a .aspx page
    4) Drop a ASP.Net Login control on the page
    5) Have the user log in
    6) Direct the user to the LightSwitch application and they will be logged in

    If you have placed the LightSwitch application inside a website that already has authentication, LightSwitch will consider the person logged in if they are logged in with your existing application.

    The reason the DotNetNuke example is going to take me some time is I have to show how to put all the web.config keys that LightSwitch needs into the existing DotNetNuke web.config. I also have to show how to dynamically load the .xap file LightSwitch needs.

    Now, the reason I have been up for THE LAST 8 HOURS STRAIT (it's almost 2:00am my time), is that I think I have figured out how to invoke the LightSwitch domain layer from asp.net server side code (so that any business rules you have created are still properly enforced).

    My desire is to allow you to deploy a LightSwitch application, yet still have one or two pages that people can get to on their IPad :) ...

    I cover the basic process here:
    http://openlightgroup.net/Blog/tabid/58/EntryId/163/HTML-including-HTML-5-and-LightSwitch-at-the-same-time.aspx

    but, I am working on a fully fleshed out example...

    http://www.adefwebserver.com

    http://lightswitch.adefwebserver.com

    Wednesday, March 16, 2011 8:29 AM
  • Thanks for that information Michael. If you can plug it into a standard ASP.NET website like you've described, it potentially hooks into the membership and role providers that are configured for the actual website. In that case one should be able to configure the website to use custom membership and role providers and LS should still pick that up. Can someone from MS please confirm?

    In the case where it picks up the membership and role providers from the ASP.NET website, how does one configure permissions in the LS app I wonder?

    Interesting findings though!

    Regards

    Wednesday, March 16, 2011 9:39 AM
  • Thanks for that information Michael. If you can plug it into a standard ASP.NET website like you've described, it potentially hooks into the membership and role providers that are configured for the actual website. In that case one should be able to configure the website to use custom membership and role providers and LS should still pick that up. Can someone from MS please confirm?

    In the case where it picks up the membership and role providers from the ASP.NET website, how does one configure permissions in the LS app I wonder?

    Interesting findings though!

    Regards

    Open the deployed 3-tier application in Visual Studio.

    If you drop a ASP.NET Login control on a .aspx page, you can click on "Login Tasks" and select "Administer Website".

    You can also select Website from the Visual Studio Toolbar and then ASP.NET Configuration.

    This takes you to the nomal Membership provider site.


    http://www.adefwebserver.com

    http://lightswitch.adefwebserver.com

    Wednesday, March 16, 2011 1:17 PM
  • @Steve/Michael;

    I'm not sure if you didn't read my question carefully or just trying to offer a different route. I'm NOT asking to use ASP.Net or DNN or PHP or others to create login screen or User registration. The only thing that will be shared with Asp.Net, is the membership/role/provider system that both Silverlight and Lightswitch use. So, I don't know how it got diverted to DNN or "dropping a ASP.Net Login control" came into the picture?

    My question was specifically related to LS and creating a custom User Registration form that the supervisor will use to create users in the company. As a user gets created, a series of database tables will get populated, the user profile in ASP.Net will get created and some other actions that are all codes in the LS being executed. All these actions are done INSIDE of the LS as a new user being created.

    Same thing, I need to create my own Login in LS to ask specific question and upon authentication, run a series of actions depending on the role of the user. Again, this is done in LS and not in ASP.Net or DNN. Users will not be using ASP.Net for login or User Registration.

    As in WCF RIA and Silverlight, we are provided with ASP.Net API to perform login, logout, create user, update user and etc., my question is, can we create custom user registration and these tasks via LS and being able to call these API directly from LS?

    I had asked this question months ago and didn't get a direct answer and I said I'll differ it to Beta 2.

    Thanks!


    ..Ben
    Wednesday, March 16, 2011 1:39 PM
  • Ben, I was attempting to answer your question "Can we as of Beta 2 control user creation and bypassing LS std. form".

    DotNetNuke allows you to create users and roles and LightSwitch will honor these.

    I actually felt I was answering the question.

    http://www.adefwebserver.com

    http://lightswitch.adefwebserver.com

    Wednesday, March 16, 2011 2:16 PM
  • i Ben,

    a) I have all the ASP.Net membership tables included in my current database. Can LS use these set of tables and not creating a new database with membership for LS?

     

    Yes, you can use an existing ASP.Net database to store a LS app’s roles and users.  While this is not an officially supported scenario (and therefor not guaranteed to continue to work in v2) it is workable with some customization of your web.config file.  Are you hoping to make use of roles and users you already have in your existing ASP.Net auth tables or are you just looking to have your LS app store auth data in a central location?

     

    My question was specifically related to LS and creating a custom User Registration form that the supervisor will use to create users in the company. As a user gets created, a series of database tables will get populated, the user profile in ASP.Net will get created and some other actions that are all codes in the LS being executed. All these actions are done INSIDE of the LS as a new user being created.

    Same thing, I need to create my own Login in LS to ask specific question and upon authentication, run a series of actions depending on the role of the user. Again, this is done in LS and not in ASP.Net or DNN. Users will not be using ASP.Net for login or User Registration.

     

     

    The simple answer to this question is, no.  Inside LightSwitch you cannot create a custom login form. 

    However, you can create your own login.aspx page that uses ASP.Net to authenticate users in your own unique way (collecting more data in your case) and then pass those authenticated users into your LightSwitch app without them having to login again.  Does this possibly meet your need?

     

    Valerie

     


    Valerie G. Andersen
    Wednesday, March 16, 2011 4:57 PM

  • Hi Valerie;

    Are you hoping to make use of roles and users you already have in your existing ASP.Net auth tables or are you just looking to have your LS app store auth data in a central location?

    Good question.

    I'm developing a project in Silverlight with Ria Services right now which uses the ASP.Net membership system. In THIS project due to its nature I have all the membership tables created in the same database as the rest of the tables. It's just much better than bridging over to another database.

    For future which seems to be a very good way of doing it, I'm hoping to keep everything central. So yes to both questions.

     

    However, you can create your own login.aspx page that uses ASP.Net to authenticate users in your own unique way (collecting more data in your case) and then pass those authenticated users into your LightSwitch app without them having to login again.

    I knew that in Beta 1, although there was a minor bug that didn't see the already authenticated user, but I was told that is fixed for beta.

    What I was left unanswered, was If I can do two things:

    a) Create my own Login. Now you're saying I cannot.

    b) Create my own "User create/registration". You didn't address that. Could you please cover that?

    However, you can create your own login.aspx page that uses ASP.Net to authenticate users in your own unique way (collecting more data in your case) and then pass those authenticated users into your LightSwitch app without them having to login again

    I really want to have the full solution under the umbrella of LS. I might need the user to work in Out of Browser mode without using browser. It's just doesn't look right to go to ASP.Net login and then switch over to LS. Not a professional looking solution.

    Does this possibly meet your need?

    I "might" be able to get away with LS login, but the bigger and more important question is, can I create my own users ? I had explained this extensively in  the past two posts but here I'll repeat them from above:

    "My question was specifically related to LS and creating a custom User Registration form that the supervisor will use to create users in the company. As a user gets created, a series of database tables will get populated, the user profile in ASP.Net will get created and some other actions that are all codes in the LS being executed. All these actions are done INSIDE of the LS as a new user being created."

    " I need the ability to create my own "User Registration" form to present to user. The form needs to provide the user the different roles available to assign to user. During this process, I also need to store certain info into User's Profile (part of ASP.Net membership). Can we as of Beta 2 control user creation and bypassing LS std. form?"

    Hope this covers my need for creating user.

    Overall, I'm a bit underwhelm that we don't have an open access and flexibility to the membership system. A basic and generic system is good for the majority to use but that shouldn't be the "ONLY" way to do it, for a tool that allows you to build custom application.

    Right now, this limitation will kill any application that developer needs to customize the User Creation and/or Login.

    Thanks!

     

    p.s. The problem that I keep running into, is that V1 was created with the vision of using LS for departmental and "controlled environment" use and not building "Commercial" and SaaS applications that, there are more variables in the picture and the developer needs to span over the boundaries of just a group of users.

    Case in point, when building apps that many companies reside into one database and are separated from each other in a logical fashion. The user's information must be extended to identify them to which organization they belong to. And security system is a very essential part of building these types of systems.

    I can see V1 being limited to this smaller scale, but if V_Next is going to step up to the real world, the membership system needs to follow accordingly. I'm just not too happy to walk away from V1...



    ..Ben
    Thursday, March 17, 2011 4:38 AM
  • Hi Ben,

    I'm hoping we're going to be able to create custom role providers (& in your case custom user providers) that can be used with the built-in ASP.NET membership functions.

    I've had a quick look, but it was a bit complicated, so I put in on the back burner for "later".

    My need is fairly simple. I need to be able to add a couple of fields ro "roles" so I can show "categories" of roles in various screens in the app. Obviously those fields don't exist in the ASP.NET roles.

    It would be REALLY helpful if the LS team could give us some guidance in the form of some example code for a custom role/user provider in the context of using it with LS.

    Yann


    Thursday, March 17, 2011 6:36 AM
  • First to address the issue of sharing one central authentication database.  This scenario requires some manual configuration after deployment. 

     

    First, you need to make some changes to your web.config file on the server at your deployed location. 

    ·         You need to define a new connection string for your authentication database.

    ·         You need to update the ConnectionStringName property in the 3 ASP.Net provider strings

      <connectionStrings>

        <add name="_IntrinsicData" connectionString="Data Source=myDBServer1;Initial Catalog=Application8;Integrated Security=False;User ID=app1login;Password=somepassword#1;Pooling=True;Connect Timeout=30;User Instance=False" />

        <add name="_AuthData" connectionString="Data Source=MyDBServer2;Initial Catalog=MyAuthDB;Integrated Security=False;User ID=app1login2;Password=somepassword#2;Pooling=True;Connect Timeout=30;User Instance=False" />

      </connectionStrings>

    .

    .

    .

    <membership defaultProvider="AspNetMembershipProvider">

          <providers>

            <clear />

            <add name="AspNetMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="_AuthData" applicationName="Application8" requiresUniqueEmail="false" requiresQuestionAndAnswer="false" />

          </providers>

        </membership>

        <roleManager enabled="True" defaultProvider="AspNetRoleProvider">

          <providers>

            <clear />

            <add name="AspNetRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="_AuthData" applicationName="Application8" />

          </providers>

        </roleManager>

        <profile enabled="True" defaultProvider="AspNetProfileProvider">

          <providers>

            <clear />

            <add name="AspNetProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="_AuthData" applicationName="Application8" />

          </providers>

     

     

     


    Valerie G. Andersen
    Thursday, March 17, 2011 8:04 PM
  • The next changes are required ONLY if you want to share roles and users across multiple applications

    · Your apps need to use the same ApplicationName property in the provider string

    · You need to define a machine key – this must be defined the same in all applications that are sharing users

    *** It should be noted that roles have to mapped to permissions for each application individually as the permissions exist in each app uniquely (they’re defined in code) – the role to permission mapping will always be stored in the intrinsic store of each application and cannot be changed.

    <machineKey validationKey="C50B3C89CB21F4F1422FF158A5B42D0E8DB8CB5CDA1742572A487D9401E3400267682B202B746511891C1BAF47F8D25C07F6C39A104696DB51F17C529AD3CABE"

    decryptionKey="8A9BE8FD67AF6979E7D20198CFEA50DD3D3799C77AF2B72F"

    validation="ABC" />

    <membership defaultProvider="AspNetMembershipProvider">

    <providers>

    <clear />

    <add name="AspNetMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="_AuthData" applicationName="Application8" requiresUniqueEmail="false" requiresQuestionAndAnswer="false" />

    </providers>

    </membership>

    <roleManager enabled="True" defaultProvider="AspNetRoleProvider">

    <providers>

    <clear />

    <add name="AspNetRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="_AuthData" applicationName="Application8" />

    </providers>

    </roleManager>

    <profile enabled="True" defaultProvider="AspNetProfileProvider">

    <providers>

    <clear />

    <add name="AspNetProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="_AuthData" applicationName="Application8" />

    </providers>

    This change is required to allow moving between two applications without having to login again (For Forms auth only) – provided the user has permissions in both applications:

    · The cookie name must be the same for both applications

    <authentication mode="Forms">

    <forms name="Application8" />

    </authentication>

    After you’ve made the necessary changes to your web.config, then you will need to run the Microsoft.LightSwitch.SecurityAdmin.exe utility which is available in your LightSwitch install directory. This utility is used to create a new Auth administrator that has the SecurityAdministrator privilege which enables the managing of roles and users. This is done for you at deployment time (provided you chose the option) but since you’ve changed your Authentication database location, the administrator needs to be created in the new database location. You can run the utility from any location that has access to your authentication database. The call should look something like this.

    …\Program Files\Microsoft Visual Studio 10.0\LightSwitch\1.0\Tools\Microsoft.LightSwitch.SecurityAdmin.exe/createadmin /user:MyAdminUser /password:strong#Password /fullname:Admin /config:c:\....\web.config

    Now on to the question of creating your own administration screen – you certainly can do that. The API’s are available that allow you to create roles and users and map them ass necessary. Creating your own screens will require you to use custom controls for things like not showing passwords in clear text and such if you’re using forms authentication. You would also need to use custom controls if you want to do things like display the available permissions or roles in a drop-down list. It’s all doable but will be a bit of work since the access control entities are not exposed. You can find the API’s you’re interested in DataWorkspace.SecurityData.

    I’ve pulled together just a real simple example of a custom admin screen to create roles and users. This example is just to show you the API – it’s not an example of a robust experience at all (it is a working sample though). This implementation takes the basic data for roles and users and then also adds e-mail and phone number which is stored in a table in the intrinsic store. Hopefully this will help get you started:

    using System;

    using System.Linq;

    using System.IO;

    using System.IO.IsolatedStorage;

    using System.Collections.Generic;

    using Microsoft.LightSwitch;

    using Microsoft.LightSwitch.Framework.Client;

    using Microsoft.LightSwitch.Presentation;

    using Microsoft.LightSwitch.Presentation.Extensions;

    using Microsoft.LightSwitch.Security;

    namespace LightSwitchApplication

    {

    public partial class CustAdmin

    {

    partial void CustAdmin_Saving(ref bool handled)

    {

    Role newRole = null;

    UserRegistration newUser = null;

    RolePermission newRolePermission = null;

    Permission newUserPerm = null;

    this.RoleInput = this.RoleInput.ToLower();

    this.UserNameInput = this.UserNameInput.ToLower();

    //check if the user exists - if one exists throw an error

    IDataServiceQueryable<UserRegistration> userquery = from myuser in this.DataWorkspace.SecurityData.UserRegistrations

    where myuser.UserName == this.UserNameInput

    select myuser;

    newUser = userquery.SingleOrDefault();

    if (newUser != null)

    throw new InvalidOperationException("The user already exists");

    //get the newUser permission to give to the new role

    //all new users get only this role initially

    //TODO alternate implementation: use a custom control and give a drop-down list of available permissions/roles

    newUserPerm = this.DataWorkspace.SecurityData.Permissions_Single(Permissions.NewUser);

    //check if the role exists - if one exists, use that role

    IDataServiceQueryable<Role> rolequery = from myrole in this.DataWorkspace.SecurityData.Roles

    where myrole.Name == this.RoleInput

    select myrole;

    newRole = rolequery.SingleOrDefault();

    //if no existing role was found, create a new one.

    if (newRole == null)

    {

    newRole = this.DataWorkspace.SecurityData.Roles.AddNew();

    newRole.Name = this.RoleInput;

    //add the permission to the role

    newRolePermission = this.DataWorkspace.SecurityData.RolePermissions.AddNew();

    newRolePermission.Permission = newUserPerm;

    newRolePermission.Role = newRole;

    }

    //only look for existing role permission mapping on existing roles

    else

    {

    //see if there is already a mapping for this role and permission

    IDataServiceQueryable<RolePermission> rolePermissionQuery = from myroleperm in this.DataWorkspace.SecurityData.RolePermissions

    where (myroleperm.PermissionId == Permissions.NewUser && myroleperm.RoleName.ToLower() == this.RoleInput)

    select myroleperm;

    newRolePermission = rolePermissionQuery.SingleOrDefault();

    //the role permission doesn't exist so add it

    }

    //if no rolePermission exists

    if (newRolePermission == null)

    {

    newRolePermission = this.DataWorkspace.SecurityData.RolePermissions.AddNew();

    newRolePermission.Permission = newUserPerm;

    newRolePermission.Role = newRole;

    }

    newUser = this.DataWorkspace.SecurityData.UserRegistrations.AddNew();

    newUser.UserName = this.UserNameInput;

    //TODO alternate implementation: real screen would need a password input box and confirm password logic for Forms auth

    newUser.Password = this.PasswordInput;

    newUser.FullName = this.DisplayNameInput;

    this.DataWorkspace.SecurityData.SaveChanges();

    RoleAssignment newRoleAssign = newUser.RoleAssignments.AddNew();

    newRoleAssign.Role= newRole;

    newRoleAssign.User = newUser;

    this.DataWorkspace.SecurityData.SaveChanges();

    }

    As you are considering alternate ways of working with your access control data you might also like to consider Matt’s approach to accessing this data – http://blogs.msdn.com/b/mthalman/archive/2010/09/20/how-to-reference-security-entities-in-lightswitch.aspx

    Hope this helps!

    Valerie


    Valerie G. Andersen
    • Proposed as answer by Valerie Andersen Thursday, March 17, 2011 8:04 PM
    • Marked as answer by Ben Hayat Thursday, March 17, 2011 9:46 PM
    Thursday, March 17, 2011 8:04 PM

  • Now, the reason I have been up for THE LAST 8 HOURS STRAIT (it's almost 2:00am my time), is that I think I have figured out how to invoke the LightSwitch domain layer from asp.net server side code (so that any business rules you have created are still properly enforced).

    Can you please share how one would go about this?
    There is always a way. You just have to find it.
    Thursday, March 17, 2011 9:52 PM
  • Thank you Valerie for the complete coverage. My Silverlight's web.config is very similar to your Web.conf suggestion and I can see the reasoning.

    I have to give it some thought and evaluate whether my approach of using LS for this project is the appropriate direction or not. It's not fun to try to make something do that was not designed for.

    I'm sure your sample will be very helpful once I get to this part, if I choose to use LS for this project.

    Thank you!


    ..Ben
    Thursday, March 17, 2011 10:27 PM
  • I've made progress on this topic:

    1) Created a new LS web app talking to an existing database

    2) Published to a Zip install file

    3) Installed to IIS7 on my local machine by manually extracting the deployment from the zip file (IIS7 gives my an error about not having admin rights if I try the automated install)

    4) Created a new set of CustomMembershipProvider, CustomRoleProvider and CustomProfileProvider classes with minimal implementation (has username and password hard coded for now) and deployd to the bin folder above

    5) Edited the web.config file in the above deployment to reference the 3 x custom providers above

    6) Created a SQL create script of the RolePermission table from a sample LS app and created that table in the existing app database used for the app above

    7) Changed the _IntrinsicData connection string in the web.config to point at the existing app database

    8) Changed the connection string for the existing database app in the same web.config to point at the existing database (could maybe do this during LS publish?)

    Run the app inside IE and FF and I can log in correctly as per the hard coded username and password put into the CustomMembershipProvider.

    My conclusion from this is that you *can* make a LS app work with a set of CustomMembershipProvider, CustomRoleProvider and CustomProfileProvider classes - which is a must for me, although there is more to experiment with Permissions and to see whether the LS user/role/permission built-in editing can work with this. Even if the LS built-in user/role/permission editing will not work with this, I don't see a problem with that as all those are just "tables" and we know how easy it is to edit tables in LS, right?

    Encouraging so far...

    Regards

     


    Xander
    Tuesday, March 22, 2011 7:58 AM
  • Given that we cannot customize the LS login dialog (and this is a real pity), I'm planning to go the way of creating an ASPX landing page where the user logs in and is then redirected to the LS application. My application will be internet facing and although it will not have public registration functionality, it does need [forgot my password] functionality. The only way I can see to implement that is to have that ASPX login page with a link to have a password reset/reminder email sent.

    So Ben I think in summary, and going back to your original questions in the first post above:

    a) yes, by using either the default ASP membership provider or creating a custom membership provider

    b) only achievable by creating an ASPX login page

    c) same as b) above

    I'll report back once I have the ASPX login page working.

    Regards


    Xander
    Wednesday, March 23, 2011 8:57 AM
  • Given that we cannot customize the LS login dialog (and this is a real pity), I'm planning to go the way of creating an ASPX landing page where the user logs in and is then redirected to the LS application. My application will be internet facing and although it will not have public registration functionality, it does need [forgot my password] functionality. The only way I can see to implement that is to have that ASPX login page with a link to have a password reset/reminder email sent.

    So Ben I think in summary, and going back to your original questions in the first post above:

    a) yes, by using either the default ASP membership provider or creating a custom membership provider

    b) only achievable by creating an ASPX login page

    c) same as b) above

    I'll report back once I have the ASPX login page working.

    Regards


    Xander

    All of this is consistant with what I found.

    A cool thing to see is that if you hit the LightSwitch app and log in, it will also log the user into your .asp.net site site...


    http://www.adefwebserver.com

    http://lightswitch.adefwebserver.com

    Wednesday, March 23, 2011 9:16 PM
  • One more thing. If you do all this, the user will still see a box that allows them to change their password. You may not want this because you have customized things.

    I asked the team how to turn this off and basically they said you can create a custom shell that doesn't have the change password button.

    easy :)


    http://www.adefwebserver.com

    http://lightswitch.adefwebserver.com

    Wednesday, March 23, 2011 10:01 PM
  • Given that we cannot customize the LS login dialog (and this is a real pity), I'm planning to go the way of creating an ASPX landing page where the user logs in and is then redirected to the LS application. My application will be internet facing and although it will not have public registration functionality, it does need [forgot my password] functionality. The only way I can see to implement that is to have that ASPX login page with a link to have a password reset/reminder email sent.

    So Ben I think in summary, and going back to your original questions in the first post above:

    a) yes, by using either the default ASP membership provider or creating a custom membership provider

    b) only achievable by creating an ASPX login page

    c) same as b) above

    I'll report back once I have the ASPX login page working.

    Regards


    Xander

    Xander, thank you for your participation in this discussion. I've reached to the same conclusion as you have. Now, it's matter of making the decision "how" and "if" to go about workarounds.

    Currently, the core of the application is being developed in SL. The Consumer/viewer module will be only in ASP.Net to be able to run on any device. The third module is the System Admin that oversees all the activities that are happening. This is the module that I had considered using LS. But I don't want to give up certain important features by going with LS (just because I can get it done faster) and then pay the price later. In my years of programming I've learned not jump into fire too fast. :-)

    ..Ben
    Thursday, March 24, 2011 4:07 AM
  • Have confirmed that if you:

    1) update the <LS project>\ServerGenerated\web.config with custom provider settings and
    2) add an _AuthData connection string into <LS project>\ServerGenerated\web.config pointing at your own database (after adding the RolePermissions table to your own database)

    that you can run the LS app from within VS.NET and use the Adminsitration Roles and Users editing facility to maintain and edit your Roles and Users.

    Michael, in fact even the [Change Password] function will work :)

    You have to implement all the required methods on the custom membership and role providers of course. One easy way is to run the LS app and implement the required method - one at a time - as the app breaks on such an unimplemented method. I did not go all the way to the end, implementing all of them, as I'm not going to use all that functionality in my app, but I'm pretty sure, based on the ones I did implement, that it will all work right to the end.

    Having said all the above, I'm not going to go that way as my user maintenance functionality is too complicated to support through the standard membership and role provider mechanism. I have the following additional requirements:

    - complex filtering of users depending on logged in user (users are also linked to "entities" in my app and it's hierarchical and a bit complex)
    - I need additional fields to edit and maintain on a user, over and above what is provided out of the box

    To that extent, my plan of action is as follows:

    1. Implement the very minimal basic custom membership, role and profile providers that work with my app database structure
    2. Insert custom providers into <LS project>\ServerGenerated\web.config file
    3. Insert _AuthData connection string into <LS project>\ServerGenerated\web.config file
    3. Add RolePermissions table to my app database
    4. Add Permissions table to my app database and add all permissions manually in there as they are hard coded (no need for maintenance)
    5. Add exact same permissions into LS to use during debugging (still need to figure out where LS stores this - in the .lsml?)
    6. Create admin screens in LS to edit Users, Roles, RolePermissions (like the ones built into LS) - including my additional filtering, etc
    7. Make sure the custom membership provider methods are implemented to support password changing (to support default LS shell)
    8. Implement HasPermission() method in business layer to read and validate permissions from the database - don't want to use LS lib as backend should not depend on LS (even if this was possible)
    9. Create an ASPX landing page where the user will log in with a [forgot my password] function

    Remember that the overall architecture of my first app is one where LS is only used for doing the UI. Everything else is hidden behind a RIA domain service with appropriate business layer and data layer with some additional WCF publicly exposed services

    Ben, like you, I have been contemplating whether to use LS or not. My deadline is tight and there is no room for rework. I've not really even played that much with the UI design inside LS (other than a small app I did as a test the other evening), but I'm assuming that custom controls and shell extensions will save my bacon should I run into trouble - at least that is what Michael said with his "get out of jail card" story :). Although these work arounds described here are time consuming (especially figuring out how to do them), I'm betting on the fact that my UI development is going to be so quick that it would have been all worth it. Fingers crossed :)

    Edit: just to clarify, all of the above will also work with the standard ASP.NET providers (as per Valerie's post/s above) if you are happy with the standard ASP user + security tables in your own database. I have totally different user + security tables in my database, that is why I need the custom providers.

    Regards


    Xander






    • Edited by novascape Friday, March 25, 2011 2:32 AM
    Friday, March 25, 2011 2:23 AM
  • Have confirmed that if you:

    1) update the <LS project>\ServerGenerated\web.config with custom provider settings and
    2) add an _AuthData connection string into <LS project>\ServerGenerated\web.config pointing at your own database (after adding the RolePermissions table to your own database)

    that you can run the LS app from within VS.NET and use the Adminsitration Roles and Users editing facility to maintain and edit your Roles and Users.

    Michael, in fact even the [Change Password] function will work :)

    You have to implement all the required methods on the custom membership and role providers of course. One easy way is to run the LS app and implement the required method - one at a time - as the app breaks on such an unimplemented method. I did not go all the way to the end, implementing all of them, as I'm not going to use all that functionality in my app, but I'm pretty sure, based on the ones I did implement, that it will all work right to the end.

    Having said all the above, I'm not going to go that way as my user maintenance functionality is too complicated to support through the standard membership and role provider mechanism. I have the following additional requirements:

    - complex filtering of users depending on logged in user (users are also linked to "entities" in my app and it's hierarchical and a bit complex)
    - I need additional fields to edit and maintain on a user, over and above what is provided out of the box

    To that extent, my plan of action is as follows:

    1. Implement the very minimal basic custom membership, role and profile providers that work with my app database structure
    2. Insert custom providers into <LS project>\ServerGenerated\web.config file
    3. Insert _AuthData connection string into <LS project>\ServerGenerated\web.config file
    3. Add RolePermissions table to my app database
    4. Add Permissions table to my app database and add all permissions manually in there as they are hard coded (no need for maintenance)
    5. Add exact same permissions into LS to use during debugging (still need to figure out where LS stores this - in the .lsml?)
    6. Create admin screens in LS to edit Users, Roles, RolePermissions (like the ones built into LS) - including my additional filtering, etc
    7. Make sure the EsisMembershipProvider methods are implemented to support password changing (to support default LS shell)
    8. Implement HasPermission() method in business layer to read and validate permissions from the database - don't want to use LS lib as backend should not depend on LS (even if this was possible)
    9. Create an ASPX landing page where the user will log in with a [forgot my password] function

    Remember that the overall architecture of my first app is one where LS is only used for doing the UI. Everything else is hidden behind a RIA domain service with appropriate business layer and data layer with some additional WCF publicly exposed services

    Ben, like you, I have been contemplating whether to use LS or not. My deadline is tight and there is no room for rework. I've not really even played that much with the UI design inside LS (other than a small app I did as a test the other evening), but I'm assuming that custom controls and shell extensions will save my bacon should I run into trouble. Although these work arounds described here are time consuming (especially figuring out how to do them), I'm betting on the fact that my UI development is going to be so quick that it would have been all worth it. Fingers crossed :)

    Regards
    Xander



    Good luck Xander. I'll wait for post V1 or V2. Gota finish my main app in SL first. I tell you what, having the full freedom in SL really spoils you :-)

    ..Ben
    Friday, March 25, 2011 2:30 AM
  • Thanks Ben, I probably need all the luck I can get :)  Notwithstanding my point above about not having any time for rework, one of the reasons that I'm going the way of just using LS to do the "UI", is that it will allow me to switch to something else later if I run into issues.
    Xander
    Friday, March 25, 2011 2:42 AM
  • Ben, off topic, but as a matter of interest, do you use any 3rd party frameworks e.g Catel, etc with Silverlight?

    Thanks


    Xander
    Friday, March 25, 2011 2:46 AM
  • Ben, off topic, but as a matter of interest, do you use any 3rd party frameworks e.g Catel, etc with Silverlight?

    Thanks


    Xander

    I primarily use Telerik complete system. Been with the product since CTP1 :-) and VERY happy with the product, support and company. I've used others for some testing and comparisons, but Telerik Rocks. Hopefully they'll do some stuff for LS. But for SL/WPF/ASP, you just can't ask for more.

    Now, the above answer was related to controls, but as far as Framework like MVVM, I plan to use Prism 4 & MEF primarily and not third party. As a Consultant, every single job that I run into, one of it's requirement is Prism 4 and the second is WCF RIA services.

    ..Ben
    Friday, March 25, 2011 2:52 AM
  • Hi Xander,

    I'm very interested in creating a custom provider as well (I need to add extra fields to the "role").

    Yes, the permission are stored in the lsml file, like this:

      <Permission Name="Name_Of_Permission">
        <Permission.Attributes>
          <DisplayName Value="Display Name Of Permission" />
        </Permission.Attributes>
      </Permission>

    There is also an auto-generated "Permissions.vb" file in the "Common/GeneratedArtifacts" folder that has a string constant defined for each of the permissions youe create.

      Public Const Name_Of_Permission As String = "LightSwitchApplication:Name_Of_Permission"

    This is where the ability to test user permissions in the form of Current.User.HasPermission(Permissions.Name_Of_Permission) comes from.

    Hope that's helpful & look forwward to the results of your foray into custom providers.

    Yann

    Friday, March 25, 2011 2:52 AM
  • Since I like to have integer PKs on all my tables, the RolePermissions table used by default by LS doesn't really fit with my application database schema which looks like this:

    [Users] <- [UsersRolesLink] -> [Roles] <- [RolesPermissionsLink] -> [Permissions]

    To support LS Permissions (which require the RolePermissions table to be available via the _IntrinsicData connection) I have created the following view in my main app database:

    CREATE VIEW [dbo].[RolePermissions]
    AS

    -- This view exists solely to support permissions inside the Lightswitch application.
    -- The _IntrinsicData connection string will establish a connection with this main app database
    --   to query this [RolePermissions] table to establish what permissions a user has.

    select
        Roles.RoleName,
        'LightSwitchApplication:' + Permission.PermissionName as PermissionId
    from
        Roles with (nolock)
            inner join RolesPermissionLink with (nolock) on RolesPermissionLink.RoleId = Roles.Id
            inner join Permission with (nolock) on Permission.Id = RolesPermissionLink.PermissionId 
    GO

    LS saves permissions into the RolePermissions table by prefixing the PermissionId with 'LightSwitchApplication:', hence the requirement to prefix that in the view.

    As already stated above, I will be implementing my own User/Role/Permission editing in LS so this view being read-only from a LS perspective works just fine.

    I might have to do a blog on all this when I'm done :)

    Regards


    Xander
    Saturday, March 26, 2011 12:10 AM
  • 1. Switch your LightSwitch solution to “File View”

    2. Click on Show All Files

    3. Right click on the Server Generated project and Add New Item

    4. Add the ASPX page called SingIn with the appropriate code.

      <form id=”form1″ runat=”server”><div>

     

    <p>Sign in</p>

    <asp:Label ID=”Label1″ runat=”server” Text=”User Name”></asp:Label>

    <asp:TextBox ID=”TextBox1″ runat=”server” Width=”128px”></asp:TextBox>

    <asp:Label ID=”Label2″ runat=”server” Text=”Password”></asp:Label>

    <asp:TextBox ID=”TextBox2″ runat=”server”

    TextMode=”Password” Width=”128px”></asp:TextBox>

    <asp:Button ID=”BtnSingIn” runat=”server” Text=”Sign In”

    onclick=”BtnSingIn_Click”/>

    <center><label id=”lblForgot”>Forgot password </label>

    <a href=”https://www.in4doctor.com” target=”_self”>click here</a></center>

    </div>

    </form>

    5- Now we need to write BtnSingIn_Click event:

    protected void BtnSingIn_Click(object sender, EventArgs e)

     

    {

    Microsoft.LightSwitch.Security.ServerGenerated.Implementation.User user;

    Microsoft.LightSwitch.Security.ServerGenerated.Implementation.AuthenticationService x = new Microsoft.LightSwitch.Security.ServerGenerated.Implementation.AuthenticationService();

    user = x.Login(TextBox1.Text, TextBox2.Text, false, “”);

    if (user != null)

    {

    Response.Write(“<script>window.parent.location=\”http://www.StudentCourse.Com/default.htm\”</script>”);

    } // you need to change the URL according to your Project

    }

    6. We now need to get SingIn.aspx to be included in the build output.  Right click on your project in solution explorer and select Unload Project.

    7. Right click the project and select Edit.

    8. Search the file and for default.htm.  You should find a section called _BuildFile.

    9. Underneath the _BuildFile section for default.htm, add the following.

    <_BuildFile Include=”ServerGenerated\Singin.aspx”>
    <SubFolder>
    </SubFolder>
    <PublishType>
    </PublishType>
    </_BuildFile>

    10. Now Insert your login account  the and enjoy

    ——————————————–

    Jamil Bin Milhem

    lightswitch Developer IN4ma Team

    Jordan

    Jamil.milhem@in4ma.com

    • Proposed as answer by Jamil MilheM Thursday, May 26, 2011 8:54 AM
    Wednesday, May 25, 2011 8:04 AM
  • Joe, not to be funny, but how many times are you going to post your article across these forums? It is useful information but not on every thread :)
    Xander
    Thursday, May 26, 2011 9:06 AM
  • Hi Ben

    In my opinion only get each user to invent and solve the issue that Lightswitch not cover our requirements in terms of user access control, leaving a trail of different solutions accommodated by everyone, no standardized we should try that Lightswitch development team is given the task to really understand what most of the developers of enterprise products require for our work.

    This would avoid wasting time on an old theme, rather toiled in other places of production software, and that Microsoft should already be clear what should be the solution.

    That is why I proposed this solution, which also put your opinion.

     

    http://social.msdn.microsoft.com/Forums/en-US/lightswitchgeneral/thread/af503bc2-bf82-448b-80a9-f3fad04e46c5

     

    Jaime

    Wednesday, June 01, 2011 1:21 PM
  • I've installed, uninstalled, reinstalled the LightSwitch Beta 2 Prerequisites and still get this error while trying to execute Microsoft.LightSwitch.SecurityAdmin.exe :

     

    Could not load file or assembly 'Microsoft.LightSwitch.Base.Server, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

    The system cannot find the file specified.

     

    do you have any pointers as to this happens?

    Friday, June 10, 2011 12:57 PM
  • Hi Paris,

    Where are you running SecurityAdmin.exe from? The utility is dependent on the assemblies that are in the folder it is installed with. Have you possibly copied the .exe and not the rest of the folder contents to another location?  If so, you should be able to correct the error by copying the entire Tools folder to the desired location.

    I should also make mention, the order of parameters matters with this utility and you must make sure that the utility is being run from a location that #1 has access to the web.config location you are specifying in the /config: parameter and #2 has access to the access control database specified in that webconfig via the connection string.

    …\Program Files\Microsoft Visual Studio 10.0\LightSwitch\1.0\Tools\Microsoft.LightSwitch.SecurityAdmin.exe

    /createadmin

    /user:MyAdminUser

    /password:strong#Password

    /fullname:Admin

               /config:c:\....\web.config

    I hope that helps!

    Valerie


    Valerie G. Andersen
    Friday, June 10, 2011 2:24 PM
  • Spot on, thanks Valerie!
    Tuesday, June 14, 2011 11:38 AM
  • I am trying to make this http://www.dotnetnuke.com/Resources/Blogs/EntryId/3063/Easy-DotNetNuke-LightSwitch-Deployment.aspx work and I got to accept me to log in after running Microsoft.LightSwitch.SecurityAdmin.exe. The thing now is that Michael is saying that I should be able to use the users in the DNN database to log in the LightSwitch application but I can't!

    Any pointers?

    Tuesday, June 14, 2011 12:03 PM
  • I am trying to make this http://www.dotnetnuke.com/Resources/Blogs/EntryId/3063/Easy-DotNetNuke-LightSwitch-Deployment.aspx work and I got to accept me to log in after running Microsoft.LightSwitch.SecurityAdmin.exe. The thing now is that Michael is saying that I should be able to use the users in the DNN database to log in the LightSwitch application but I can't!

    Any pointers?


    You log into the DotNetNuke site first (or any ASP.NET site that is using Forms authentication and you have copied the Machine key and the forms tag as described in: http://www.dotnetnuke.com/Resources/Blogs/EntryId/3063/Easy-DotNetNuke-LightSwitch-Deployment.aspx ).

    I have another article on the subject at:

    http://www.codeproject.com/KB/silverlight/DNNThingsForSale.aspx


    http://www.adefwebserver.com

    http://LightSwitchHelpWebsite.com

    Tuesday, June 14, 2011 12:26 PM

  • Now, the reason I have been up for THE LAST 8 HOURS STRAIT (it's almost 2:00am my time), is that I think I have figured out how to invoke the LightSwitch domain layer from asp.net server side code (so that any business rules you have created are still properly enforced).

    Can you please share how one would go about this?
    There is always a way. You just have to find it.

    I had found a way but it opens up transactions and doesn't close them :(

    http://www.adefwebserver.com

    http://LightSwitchHelpWebsite.com

    Tuesday, June 14, 2011 12:28 PM
  • I am trying to make this http://www.dotnetnuke.com/Resources/Blogs/EntryId/3063/Easy-DotNetNuke-LightSwitch-Deployment.aspx work and I got to accept me to log in after running Microsoft.LightSwitch.SecurityAdmin.exe. The thing now is that Michael is saying that I should be able to use the users in the DNN database to log in the LightSwitch application but I can't!

    Any pointers?


    You log into the DotNetNuke site first (or any ASP.NET site that is using Forms authentication and you have copied the Machine key and the forms tag as described in: http://www.dotnetnuke.com/Resources/Blogs/EntryId/3063/Easy-DotNetNuke-LightSwitch-Deployment.aspx ).

    I have another article on the subject at:

    http://www.codeproject.com/KB/silverlight/DNNThingsForSale.aspx


    http://www.adefwebserver.com

    http://LightSwitchHelpWebsite.com

    I got it, it was my fault in the end. The application name in the DNN web.config and the LightSwitch web.config weren't the same (rolls eyes). I've fixed it and now it's working properly. Thanks!
    Tuesday, June 14, 2011 1:04 PM
  • Am I supposed to see the Administrative Roles into the LightSwitch application when I log into DotNetNuke as an Administrator and then navigate to the LightSwitch Application?
    Wednesday, June 15, 2011 9:39 AM
  • Am I supposed to see the Administrative Roles into the LightSwitch application when I log into DotNetNuke as an Administrator and then navigate to the LightSwitch Application?


    No. The article:

    http://www.codeproject.com/KB/silverlight/DNNThingsForSale.aspx

    explains the process.


    http://www.adefwebserver.com

    http://LightSwitchHelpWebsite.com

    Wednesday, June 15, 2011 12:31 PM
  • Allright, thanks for all your help!
    Wednesday, June 15, 2011 12:39 PM