饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 109 页

作者:Nick Randolph/等 当前章节:15428 字 更新时间:2026-6-18 14:51

client application services. You do this by adding the <profileService> element to the <system

.web.extensions> element in the web.config file:

734 .

chaPter 33 clienT ApplicATion SerViceS

<system.web.extensions>

<scripting>

<webServices>

<profileService enabled="true"

readAccessProperties="Nickname"

writeAccessProperties="Nickname" />

<authenticationService enabled="true" requireSSL="false"/>

Code snippet web.config

Following the previous examples, you will build a custom profile provider that uses an in-memory

dictionary to store user nicknames. Note that this isn’t a good way to track profile information,

because it would be lost every time the web server recycled and would not scale out to multiple

web servers. Nevertheless, you need to add a new class, CustomProfile, to the ApplicationServices

project and set it to inherit from ProfileProvider.

c#

using System.Web.Profile;

using System.Configuration;

public class CustomProfile : ProfileProvider{

private Dictionary<string, string> nicknames =

new Dictionary<string, string>();

public override System.Configuration.SettingsPropertyValueCollection

GetPropertyValues(System.Configuration.SettingsContext context,

System.Configuration.SettingsPropertyCollection collection){

var vals = new SettingsPropertyValueCollection();

foreach (SettingsProperty setting in collection){

var value = new SettingsPropertyValue(setting);

if (nicknames.ContainsKey(setting.Name)) {

value.PropertyValue = nicknames[setting.Name];

}

vals.Add(value);

}

return vals;

}

public override void SetPropertyValues(SettingsContext context,

SettingsPropertyValueCollection collection){

foreach (SettingsPropertyValue setting in collection){

nicknames[setting.Name] = setting.PropertyValue.ToString();

}

}

// The rest of the implementation has been omitted for brevity

}

Code snippet CustomProfile.cs

settings .

735

Vb

Imports System.Configuration

Public Class CustomProfile

Inherits ProfileProvider

Private nicknames As New Dictionary(Of String, String)

Public Overrides Function GetPropertyValues(ByVal context As SettingsContext,

ByVal collection As SettingsPropertyCollection) _

As SettingsPropertyValueCollection

Dim vals As New SettingsPropertyValueCollection

For Each setting As SettingsProperty In collection

Dim value As New SettingsPropertyValue(setting)

If nicknames.ContainsKey(setting.Name) Then

value.PropertyValue = nicknames.Item(setting.Name)

End If

vals.Add(value)

Next

Return vals

End Function

Public Overrides Sub SetPropertyValues(ByVal context As SettingsContext,

ByVal collection As SettingsPropertyValueCollection)

For Each setting As SettingsPropertyValue In collection

nicknames.Item(setting.Name) = setting.PropertyValue.ToString

Next

End Sub

'The rest of the implementation has been omitted for brevity

End Class

Code snippet CustomProfile.vb

The difference with the profile service is that when you specify the provider to use in the <system

.web> element in the web.config file, you also need to declare what properties can be saved via

the profile service (see the following snippet). For these properties to be accessible via the client

application services, they must have a corresponding entry in the readAccessProperties and

writeAccessProperties attributes of the <profileService> element, shown earlier.

<profile enabled="true" defaultProvider="CustomProfile">

<providers>

<add name="CustomProfile" type="ApplicationServices.CustomProfile"/>

</providers>

<properties>

<add name="Nickname" type="string"

readOnly="false" defaultValue="{nickname}"

serializeAs="String" allowAnonymous="false" />

</properties>

</profile>

Code snippet web.config

736 .

chaPter 33 clienT ApplicATion SerViceS

As an aside, the easiest way to build a full profile service is to use the utility aspnet_regsql.exe

(typically found at c:\Windows\Microsoft.NET\Framework\v4.0.21006\aspnet_regsql.exe) to

populate an existing SQL Server database with the appropriate table structure. You can then use the

built-in SqlProfileProvider (SqlMembershipProvider and SqlRoleProvider for membership

and role providers, respectively) to store and retrieve profile information. To use this provider,

change the profile element you added earlier to the following:

<profile enabled="true" defaultProvider="CustomProfile">

<providers>

<add name="SqlProvider"

type="System.Web.Profile.SqlProfileProvider"

connectionStringName="SqlServices"

applicationName="SampleApplication"

description="SqlProfileProvider for SampleApplication" />

Note that the connectionStringName attribute needs to correspond to the name of a SQL Server

connection string located in the connectionStrings section of the web.config file.

To use the custom profile provider you have created, in the client application, you need to

specify the web settings service location on the Services tab of the project properties designer.

This location should be the same as for both the role and authentication services: http://

localhost:12345/ApplicationServices.

This is where the Visual Studio 2010 support for application settings is particularly useful. If you

now go to the Settings tab of the project properties designer and click the Load Web Settings button,

you are initially prompted for credential information, because you need to be a validated user to

access the profile service. Figure 33-3 shows this dialog with the appropriate credentials supplied.

After a valid set of credentials is entered, the profile service is interrogated and a new row is added to

the settings design surface, as shown in Figure 33-4. Here you can see that the scope of this setting is

indeed User (Web) and that the default value, specified in the web.config file, has been retrieved.

fiGure 33-3 fiGure 33-4

If you take a look at the app.config file for the client application, you will notice that a new

sectionGroup has been added to the configSections element. This simply declares the class that

will be used to process the custom section that has been added to support the new user settings.

settings .

737

<configSections>

<sectionGroup name="userSettings"

type="System.Configuration.UserSettingsGroup, System,

Version=4.0.0.0, Culture=neutral,

PublicKeyToken=b77a5c561934e089" >

<section name="ClientServices.Properties.Settings"

type="System.Configuration.ClientSettingsSection, System,

Version=4.0.0.0, Culture=neutral,

PublicKeyToken=b77a5c561934e089" allowExeDefinition=

"MachineToLocalUser" requirePermission="false" />

</sectionGroup>

</configSections>

Toward the end of the app.config file, you will see the custom section that has been created. As you

would expect, the name of the setting is Nickname and the value corresponds to the default value

specified in the web.config file in the ApplicationServices project.

<userSettings>

<ClientAppServicesVB.MySettings>

<setting name="Nickname" serializeAs="String">

<value>{nickname}</value>

</setting>

</ClientAppServicesVB.MySettings>

</userSettings>

To make use of this in code you can use the same syntax as for any other setting. Here you simply

retrieve the current value, request a new value, and then save this new value:

c#

private void Window_Loaded(object sender, RoutedEventArgs e){

// Commented out for brevity

MessageBox.Show(My.Settings.Nickname)

Properties.Settings.Default.Nickname = "Not the default Name";

My.Settings.Save()

Code snippet MainWindow.cs

Vb

Private Sub Window_Loaded(ByVal sender As System.Object,

ByVal e As System.Windows.RoutedEventArgs) _

Handles Me.Loaded

' Commented out for brevity

MessageBox.Show(My.Settings.Nickname)

My.Settings.Nickname = InputBox("Please specify a nickname:", "Nickname")

My.Settings.Save()

Code snippet MainWindow.vb

If you run this application again, the nickname you supplied the first time will be returned.

738 .

chaPter 33 clienT ApplicATion SerViceS

loGin forM

Earlier, when you were introduced to Forms authentication, you used a hard-coded username and

password to validate the user. Although it would be possible for the application to prompt the user

for credentials before calling ValidateUser with the supplied values, there is a better way that

uses the client application services framework. Instead of calling ValidateUser with a username/

password combination, you go back to supplying Nothing as the argument values and define a

credential provider; then the client application services will call the provider to determine the set of

credentials to use.

c#

private void Window_Loaded(object sender, RoutedEventArgs e){

if (Membership.ValidateUser(null, null)){

MessageBox.Show("User is valid");

Code snippet MainWindow.cs

Vb

Private Sub Window_Loaded(ByVal sender As System.Object,

ByVal e As System.Windows.RoutedEventArgs) _

Handles Me.Loaded

If Membership.ValidateUser(Nothing, Nothing) Then

MessageBox.Show("User is valid")

Code snippet MainWindow.vb

This probably sounds more complex than it is because it is relatively easy to create a credentials

provider. Start by adding a login form to the client application. Do this by selecting the Login Form

template from the Add New Item dialog and calling it LoginForm. Unfortunately, this template is

only available for VB developers as a Windows Forms form. If you want to create a WPF version

or are working in C# you will need to add a new Window to the ClientServices project and add a

TextBox (name it UsernameTextBox), a PasswordBox (name it PasswordTextBox), and two Buttons

(name them OK and Cancel). While you have the designer open, click the OK button and change the

DialogResult property to OK.

To use this login form as a credential provider, modify it to implement the

IClientFormsAuthenticationCredentialsProvider interface. An alternative strategy

would be to have a separate class that implements this interface and then displays the

login form when the GetCredentials method is called. The following code snippet

contains the code-behind file for the LoginForm class, showing the implementation of the

IClientFormsAuthenticationCredentialsProvider interface:

c#

using System.Web.ClientServices.Providers;

public partial class LoginForm : Window,

IClientFormsAuthenticationCredentialsProvider {

public LoginForm(){

login form .

739

InitializeComponent();

}

private void OK_Click(object sender, RoutedEventArgs e){

this.DialogResult = true;

this.Close();

}

private void Cancel_Click(object sender, RoutedEventArgs e){

this.DialogResult = false;

this.Close();

}

public ClientFormsAuthenticationCredentials GetCredentials(){

if (this.ShowDialog()   false) {

return new ClientFormsAuthenticationCredentials(

UsernameTextBox.Text,

PasswordTextBox.

Password,

false);

}

else{

return null;

}

}

}

Code Snippet LoginForm.xaml.cs

Vb

Imports System.Web.ClientServices.Providers

Public Class LoginForm

Implements IClientFormsAuthenticationCredentialsProvider

Public Function GetCredentials() As ClientFormsAuthenticationCredentials _

Implements IClientFormsAuthenticationCredentialsProvider.GetCredentials

If Me.ShowDialog() = Forms.DialogResult.OK Then

Return New ClientFormsAuthenticationCredentials(UsernameTextBox.Text,

PasswordTextBox.Text,

False)

Else

Return Nothing

End If

End Function

End Class

Code snippet LoginForm.vb

You will notice that the C# and VB code snippets are quite different. This

is because the C# uses a new WPF window, while the VB snippet uses the

Windows Form Login Form template.

740 .

chaPter 33 clienT ApplicATion SerViceS

As you can see from this snippet, the GetCredentials method returns

ClientFormsAuthenticationCredentials if credentials are supplied, or Nothing (VB)/null

(C#) if Cancel is clicked. Clearly this is only one way to collect credentials information, and there

is no requirement that you prompt the user for this information. (The use of dongles or employee

identification cards are common alternatives.)

With the credentials provider created, it is just a matter of informing the client application services

that they should use it. You do this via the Optional: Credentials Provider field on the Services tab

of the project properties designer, as shown in Figure 33-5.

Now when you run the application, you are prompted to enter a username and password to access

the application. This information is then passed to the membership provider on the server to

validate the user.

fiGure 33-5

offline suPPort

In the previous steps, if you had a breakpoint

in the role provider code on the server, you

may have noticed that it hit the breakpoint

only the first time you ran the application.

The reason for this is that it is caching the role

information offline. If you click the Advanced

button on the Services tab of the project

properties designer, you will see a number of

properties that can be adjusted to control this

fiGure 33-6

offline behavior, as shown in Figure 33-6.

offline support .

741

It’s the role service cache timeout that determines how frequently the server is queried for role

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页