WebAPI 权限控制解决方案——Phenix.NET企业应用软件快速开发平台.使用指南.21.WebAPI服务(三)

21.1   数据服务

21.1.1基本操作功能

Phenixヾ的数据服务,提供了如下的基本操作:


功能


Type


URI


参数


完整获取实体集合对象


GET


api/Data


分页获取实体集合对象


GET


api/Data


pageSize=[分页大小]&pageNo=[分页号]


按条件获取实体集合对象


GET


api/Data


id=[条件对象]


按条件分页获取实体集合对象


GET


api/Data


id=[条件对象]&pageSize=[分页大小]&pageNo=[分页号]


按主对象获取实体集合对象


GET


api/Data


masterId=[主对象键值]&groupName=[分组名]


按主对象分页获取实体集合对象


GET


api/Data


masterId=[主对象键值]&groupName=[分组名]&pageSize=[分页大小]&pageNo=[分页号]


获取单个实体对象


GET


api/Data


id=[主键值]


提交数据


POST


api/Data


执行服务


POST


api/Data

注:可操作的实体范围,除受到普通的权限管理控制外,仍可以受到“切片管理”(参见:《Phenix.NET企业应用软件快速开发平台.权限管理.01.简介》)的控制。

从上述接口可见,Phenixヾ的WebAPI服务提供的是通用的接口(仅实现了一个API Controller),即DataController。

这样,为了区分不同的资源,要求HTTP客户端将资源信息藏在HTTP请求的标头Header里:


Header Name


内容


适用于


说明


Phenix-Data-Name


数据名/服务名


GET、POST


在服务端注册的实体集合类全名、实体类全名、服务类全名(需实现IEntityCollection、IEntity、IService接口)


Phenix-Criteria-Name


条件名


GET


在服务端定义的条件类全名(需实现ICriteria接口)


Phenix-Master-Name


主对象名


GET


在服务端注册的实体类全名(需实现IEntity接口)

注: 实体对象的操作请求,在Http请求标头上标识“Phenix-Data-Name”内容是必须的。否则,如果没有标识上,且是未带参数的Get请求的话,服务端返回的则是Sequence(64位序列号)。

不管我们采用是什么技术、什么平台,HTTP客户端的开发,只要符合上述HTTP消息的规范要求,就能得到Phenixヾ的WebAPI数据服务。

21.1.2数据服务代理

为了说明HTTP客户端如何调用WebAPI数据服务,Phenixヾ在“Phenix.Web.Client”工程里提供了一套标准的数据服务代理类DataProxy。我们可以依照这个实例里的代码,作为样例来编写出适用于自己技术平台的HTTP客户端:

21.1.2.1   Fetch

21.1.2.1.1 方法

检索数据,分检索单个实体和实体集合,都使用到了Get操作:

/// <summary>

/// 获取实体

/// </summary>

/// <param name="dataName">数据名, 在服务端注册的实体集合类全名(需实现IEntityCollection接口)</param>

/// <param name="id">主键值</param>

/// <returns>实体</returns>

public async Task<T> FetchAsync<T>(string dataName, long id)

where T : IEntity

{

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, String.Format("{0}?id={1}", DATA_URI, id));

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(!String.IsNullOrEmpty(dataName) ? dataName : typeof(T).FullName));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return EntityHelper.JsonUnpack<T>(result);

}

/// <summary>

/// 获取实体集合

/// </summary>

/// <param name="dataName">数据名, 在服务端注册的实体集合类全名(需实现IEntityCollection接口)</param>

/// <param name="criteriaName">条件名, 在服务端定义的条件类全名(需实现ICriteria接口)</param>

/// <param name="criteria">JSON格式条件对象, 在服务端将被反序列化为criteriaName指定条件类的对象</param>

/// <param name="pageSize">分页大小</param>

/// <param name="pageNo">分页号, 从1起始</param>

/// <returns>实体集合</returns>

public async Task<T> FetchListAsync<T>(string dataName, string criteriaName, object criteria, int? pageSize, int? pageNo)

where T : IEntityCollection

{

HttpRequestMessage request;

if (criteria != null)

{

if (String.IsNullOrEmpty(criteriaName))

{

Type criteriaType = criteria.GetType();

if (!criteriaType.IsClass)

throw new ArgumentNullException("criteriaName");

criteriaName = criteriaType.FullName;

}

request = new HttpRequestMessage(HttpMethod.Get, String.Format("{0}?id={1}{2}",

DATA_URI,

Uri.EscapeDataString(criteria is string ? (string)criteria : (criteria is ICriteria ? CriteriaHelper.JsonPack(criteria) : JsonConvert.SerializeObject(criteria))),

pageSize.HasValue && pageNo.HasValue ? String.Format("&pageSize={0}&pageNo={1}", pageSize, pageNo) : null));

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebCriteriaNameHeaderName, Uri.EscapeDataString(criteriaName));

}

else

request = new HttpRequestMessage(HttpMethod.Get, String.Format("{0}{1}",

DATA_URI,

pageSize.HasValue && pageNo.HasValue ? String.Format("?pageSize={0}&pageNo={1}", pageSize, pageNo) : null));

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(!String.IsNullOrEmpty(dataName) ? dataName : typeof(T).FullName));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return EntityListHelper.JsonUnpack<T>(result);

}

检索到的数据,返回的是JSON格式的字符串,可以在客户端被转换成任何形式的数据。比如,象上述最后一行代码那样,由EntityListHelper提供的JsonUnpack()方法转换为实体集合对象。

21.1.2.1.2 调用

Fetch()函数的调用示例,代码摘录如下:

assemblyEasyList = client.DataProxy.FetchList<AssemblyEasyList>(

"Phenix.Test.使用指南._21._5.Business.AssemblyList",

"Phenix.Test.使用指南._21._5.Business.AssemblyCriteria2",

new LocalAssemblyCriteria()

{

Name = "Phenix.Test." //CriteriaOperate.Equal

});

上述黄色标示的代码段,如果被删除,WebAPI服务会查找业务类的ClassAttribute标签DefaultCriteriaType属性所申明的缺省条件类,来作为本次响应的查询类。如果未申明,则查找与业务类同名且带Criteria后缀的条件类,比如本示例找到的会是AssemblyCriteria类。这些申明的条件类,都应该实现ICriteria接口。

21.1.2.1.3 契约

在本示例中,被打包成JSON传递到服务端的查询对象,是本地客户端一个极为简单的对象:

class LocalAssemblyCriteria

{

public string Name { get; set; }

}

它只要和服务端所定义的查询类,在属性名称上能互相匹配就可以了:

[System.SerializableAttribute(), System.ComponentModel.DisplayNameAttribute("")]

public class AssemblyCriteria2 : Phenix.Business.CriteriaBase

{

[Phenix.Core.Mapping.CriteriaField(FriendlyName = "AS_NAME", Logical = Phenix.Core.Mapping.CriteriaLogical.And, Operate = Phenix.Core.Mapping.CriteriaOperate.Equal, TableName = "PH_ASSEMBLY", ColumnName = "AS_NAME")]

private string _name;

/// <summary>

/// AS_NAME

/// </summary>

[System.ComponentModel.DataAnnotations.Display(Name = "AS_NAME")]

[System.ComponentModel.DisplayName("AS_NAME")]

public string Name

{

get { return _name; }

set { _name = value; PropertyHasChanged(); }

}

}

甚至,我们可以直接传一个JSON字符串,也能达到同样的结果:

assemblyEasyList = client.DataProxy.FetchList<AssemblyEasyList>(

"Phenix.Test.使用指南._21._5.Business.AssemblyList",

"Phenix.Test.使用指南._21._5.Business.AssemblyCriteria2",

@"{""Name"":""Phenix.Test.""}"); //CriteriaOperate.Equal

最后,将执行过程中发生的Headers截录如下:

GET /api/Data?id=%7B%22Name%22%3A%22Phenix.Test.%22%7D HTTP/1.1

Phenix-Criteria-Name: Phenix.Test.%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97._21._5.Business.AssemblyCriteria2

Phenix-Data-Name: Phenix.Test.%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97._21._5.Business.AssemblyList

Phenix-Authorization: ADMIN,d48a36b5-31c9-41a6-ad35-efbcea458efc,2015-11-01 10:26:18,B7082E34BBFC95236B307E389C6796F7A29312A0D62F0BD683BF81541EB92044F8F4CE263C3AFC09116C14FD88564A4F41E5DFE1E0D755336F47465046E51CB0

Host: 10.0.0.11:8080

21.1.2.2   Save

21.1.2.2.1 方法

提交的数据,可以是单个实体,也可以是实体集合,且允许包含它们的树状结构。

提交的操作,不管是update还是insert、delete,使用的都是Post操作(需要对象能反映出当前的编辑状态):

/// <summary>

/// 提交实体

/// </summary>

/// <param name="dataName">数据名, 在服务端注册的实体类全名(需实现IEntity接口)</param>

/// <param name="entity">实体</param>

/// <returns>成功数量</returns>

public async Task<int> SaveAsync(string dataName, IEntity entity)

{

if (entity == null)

return 0;

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, DATA_URI);

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(!String.IsNullOrEmpty(dataName) ? dataName : entity.GetType().FullName));

request.Content = new StringContent(EntityHelper.JsonPackChanged(entity));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return (int)Utilities.ChangeType(result, typeof(int));

}

/// <summary>

/// 提交实体集合

/// </summary>

/// <param name="dataName">数据名, 在服务端注册的实体集合类/实体类全名(需实现IEntityCollection/IEntity接口)</param>

/// <param name="entityCollection">实体集合</param>

/// <returns>成功数量</returns>

public async Task<int> SaveAsync(string dataName, IEntityCollection entityCollection)

{

if (entityCollection == null)

return 0;

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, DATA_URI);

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(!String.IsNullOrEmpty(dataName) ? dataName : entityCollection.GetType().FullName));

request.Content = new StringContent(EntityListHelper.JsonPackChanged(entityCollection));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return (int)Utilities.ChangeType(result, typeof(int));

}

/// <summary>

/// 提交对象

/// </summary>

/// <param name="dataName">数据名, 在服务端注册的实体集合类/实体类全名(需实现IEntityCollection/IEntity接口)</param>

/// <param name="obj">JSON格式对象, 将被传到服务端, 需包含IsNew、IsSelfDeleted、IsSelfDirty属性以指明对象状态</param>

/// <returns>成功数量</returns>

public async Task<int> SaveAsync(string dataName, object obj)

{

if (obj == null)

return 0;

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, DATA_URI);

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(dataName));

request.Content = new StringContent(obj is string ? (string)obj : JsonConvert.SerializeObject(obj));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return (int)Utilities.ChangeType(result, typeof(int));

}

函数返回的是成功提交的纪录数。如果未能成功提交,服务端返回的是异常提示信息,在客户端被封装在HttpRequestException异常对象里抛出。

21.1.2.2.2 调用

Save()函数的调用示例代码如下:

count = client.DataProxy.Save(

"Phenix.Test.使用指南._21._5.Business.Assembly",

new LocalAssembly()

{

IsSelfDirty = true,

AS_ID = assemblyId,

Caption = Sequence.Value.ToString()

});

21.1.2.2.3 契约

在本示例中,被打包成JSON传递到服务端的数据对象,是本地客户端一个极为简单的对象:

class LocalAssembly

{

/// <summary>

/// 新增状态

/// </summary>

public bool IsNew { get; set; }

/// <summary>

/// 删除状态

/// </summary>

public bool IsSelfDeleted { get; set; }

/// <summary>

/// 更新状态

/// </summary>

public bool IsSelfDirty { get; set; }

public long? AS_ID { get; set; }

public string Caption { get; set; }

}

上述黄色标示的代码段,是表示当前对象的编辑状态,这被用来告知服务端,应该如何提交本对象的数据。如果没有这些编辑状态属性,服务端将默认为这个对象处于IsSelfDirty = true状态。

数据对象,应该包含PrimaryKey属性(本示例为AS_ID属性),否则服务端是无法持久化这个对象的。而且,所有需要被持久化属性的名称,都应该和服务端的实体类定义互相匹配。

同查询对象一样,数据对象也可以直接传JSON字符串。

最后,将执行过程中发生的Headers截录如下:

POST /api/Data HTTP/1.1

Phenix-Data-Name: Phenix.Test.%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97._21._5.Business.Assembly

Phenix-Authorization: ADMIN,58733271-1be1-4232-a931-6110cc5f1d83,2015-11-01 11:11:04,E3774F2B6FF6406791108EA47BBE54A667BF9D249F6583F6AB5309081A68D7E54FC4E25BDB25661B522FAFC5BE75E74AD1B3F3D63F5C9B8039F7C93996A7B915

Content-Type: text/plain; charset=utf-8

Host: 10.0.0.11:8080

Content-Length: 108

Expect: 100-continue

21.1.2.3   Execute

21.1.2.3.1 方法

执行服务,实质上是CSLA的Command模式在WebAPI上的翻版,是把WebAPI当成执行服务引擎来使用,HTTP动词是Post:

/// <summary>

/// 执行服务

/// </summary>

/// <param name="serviceName">服务名, 在服务端注册的服务类全名(需实现IService接口)</param>

/// <param name="service">服务</param>

/// <returns>服务结果</returns>

public async Task<T> ExecuteAsync<T>(string serviceName, T service)

where T : IService

{

if (service == null)

throw new ArgumentNullException("service");

Type type = service.GetType();

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, DATA_URI);

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(!String.IsNullOrEmpty(serviceName) ? serviceName : type.FullName));

request.Content = new StringContent(JsonConvert.SerializeObject(service));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return (T)JsonConvert.DeserializeObject(result, type);

}

/// <summary>

/// 执行服务

/// </summary>

/// <param name="serviceName">服务名, 在服务端注册的服务类全名(需实现IService接口)</param>

/// <param name="obj">JSON格式对象, 将被传到服务端</param>

/// <returns>服务结果</returns>

public async Task<object> ExecuteAsync(string serviceName, object obj)

{

if (obj == null)

throw new ArgumentNullException("obj");

Type type = obj.GetType();

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, DATA_URI);

request.Headers.Add(Phenix.Web.Client.Properties.Settings.Default.WebDataNameHeaderName, Uri.EscapeDataString(serviceName));

request.Content = new StringContent(obj is string ? (string)obj : JsonConvert.SerializeObject(obj));

HttpResponseMessage response = await _httpClient.SendAsync(request);

string result = await response.Content.ReadAsStringAsync();

if (response.StatusCode != HttpStatusCode.OK)

throw new HttpRequestException(result);

return obj is string ? result : JsonConvert.DeserializeObject(result, type);

}

这为我们开发WebAPI服务提供了强大的灵活性,可以纯粹以面向对象的形式编写服务端的业务逻辑代码:

[JsonObject(MemberSerialization.Fields)]

[System.SerializableAttribute()]

public class Service : Phenix.Core.Data.ServiceBase<Service> //Phenix.Business.CommandBase<Service>

{

public Service()

{

}

private string _assembly;

public Assembly Assembly

{

get { return Phenix.Core.Mapping.EntityHelper.JsonUnpack<Assembly>(_assembly); }

set { _assembly = Phenix.Core.Mapping.EntityHelper.JsonPack(value); }

}

/// <summary>

/// 处理执行指令(在运行持久层的程序域里被调用)

/// </summary>

protected override void DoExecute()

{

Assembly assembly = Assembly;

assembly.Caption = assembly.Caption + "被服务端改写";

Assembly = assembly;

EventLog.Save(Phenix.Core.Security.UserPrincipal.User, MethodBase.GetCurrentMethod(),

assembly.GetOldValue(Assembly.CaptionProperty) + "->" + assembly.Caption);

}

}

仅需继承自Phenix.Core.Data.ServiceBase,或者实现Phenix.Core.Mapping.IService接口:

21.1.2.3.2 调用

Execute()函数的调用示例代码如下:

Service service = client.DataProxy.Execute(

new Service()

{

Assembly = assembly

});

21.1.2.3.3 契约

在本示例中,客户端和服务端共享了同一个Service类,这在实际开发场景下,完全可以不必这么实现。同前文的做法一样,客户端可以使用一个简单的对象,将需要传递的属性命名与Service类的定义达成一致(本示例是Assembly属性)即可,或者直接传递JSON格式的字符串,都是可以得到相同的结果。

最后,将执行过程中发生的Headers截录如下:

POST /api/Data HTTP/1.1

Phenix-Data-Name: Phenix.Test.%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97._21._5.Business.Service

Phenix-Authorization: ADMIN,4534dfeb-35e0-44ab-963f-96c71b778cbc,2015-11-01 12:15:27,63A955F8056353BFDBDDE2FC1A8CF1D879DEA3C244EB64D1702810836F71FBCDEEAE66D0E5063542C765F2720649E076C07358A8A20A0D5B65EBC0CAFB3F72DE

Content-Type: text/plain; charset=utf-8

Host: 10.0.0.11:8080

Content-Length: 4489

Expect: 100-continue

21.1.3注册服务端事件

Phenixヾ的WebAPI服务不同于CSLA在remoting/WCF架构下的移动对象模式,不可能将数据封装成实体对象,而是纯粹的数据持久层服务(相对来说,在牺牲了业务框架特性的前提下,WebAPI服务在小批量数据下的Fetch和Save性能,理论上要优于remoting服务)。所以,业务类(继承自BusinessBase)上的服务端事件函数(比如OnSavingSelf系列函数等)都不可能被WebAPI服务调用到,业务规则(继承自ObjectRule)也不可能被WebAPI服务调用到。

为补偿因缺失上述这些业务框架特性所带来的服务端业务逻辑干预能力的弱化,Phenixヾ提供了一系列的服务端事件及其注册机制:

服务端事件,分为Fetch、Save处理过程的前事件和后事件,被定义在了IData接口里。

前事件可以拦截到客户端传递过来的数据(比如查询条件)并干预WebAPI数据服务的处理(或直接自行处理),而后事件可拦截到WebAPI数据服务的处理结果。

要注册上服务端事件,需用到AppHub的Data属性,Data属性实现了IData接口中一系列的服务端事件注册函数。

AppHub所在程序集是Phenix.Services.Library,我们开发的Business如需拦截服务端事件,就应该引用它:

服务端事件的注册和注销,都是在服务端被调用的,服务端事件的执行也应该运行在服务端。为此,我们要用到Phenixヾ提供的插件Host。具体方法是,在Business程序集里新增一个Plugin类,编译后添加到插件Host中:

Plugin类代码如下:

public class Plugin : PluginBase<Plugin>

{

public Plugin()

: base() { }

#region 方法

#region 覆写 PluginBase

/// <summary>

/// 启动

/// 由 PluginHost 调用

/// </summary>

/// <returns>确定启动</returns>

protected override bool Start()

{

AppHub.Data.FetchingRegister(typeof(Assembly), FetchingEventHandler);

AppHub.Data.FetchedRegister(typeof(Assembly), FetchedEventHandler);

AppHub.Data.FetchingRegister(typeof(AssemblyList), FetchingEventHandler);

AppHub.Data.FetchedRegister(typeof(AssemblyList), FetchedEventHandler);

AppHub.Data.SavingRegister(typeof(Assembly), SavingEventHandler);

AppHub.Data.SavedRegister(typeof(Assembly), SavedEventHandler);

AppHub.Data.SavingRegister(typeof(AssemblyList), SavingEventHandler);

AppHub.Data.SavedRegister(typeof(AssemblyList), SavedEventHandler);

return true;

}

/// <summary>

/// 暂停

/// 由 PluginHost 调用

/// </summary>

/// <returns>确定停止</returns>

protected override bool Suspend()

{

AppHub.Data.FetchingUnregister(typeof(Assembly), FetchingEventHandler);

AppHub.Data.FetchedUnregister(typeof(Assembly), FetchedEventHandler);

AppHub.Data.FetchingUnregister(typeof(AssemblyList), FetchingEventHandler);

AppHub.Data.FetchedUnregister(typeof(AssemblyList), FetchedEventHandler);

AppHub.Data.SavingUnregister(typeof(Assembly), SavingEventHandler);

AppHub.Data.SavedUnregister(typeof(Assembly), SavedEventHandler);

AppHub.Data.SavingUnregister(typeof(AssemblyList), SavingEventHandler);

AppHub.Data.SavedUnregister(typeof(AssemblyList), SavedEventHandler);

return true;

}

#endregion

/// <summary>

/// 检索前事件处理函数

/// </summary>

public void FetchingEventHandler(FetchEventArgs e)

{

EventLog.Save(Phenix.Core.Security.UserPrincipal.User, MethodBase.GetCurrentMethod(), CriteriaHelper.JsonPack(e.Criterions.Criteria));

}

/// <summary>

/// 检索后事件处理函数

/// </summary>

public void FetchedEventHandler(FetchEventArgs e)

{

EventLog.Save(Phenix.Core.Security.UserPrincipal.User, MethodBase.GetCurrentMethod(), e.Result);

}

/// <summary>

/// 提交前事件处理函数

/// </summary>

public void SavingEventHandler(SaveEventArgs e)

{

EventLog.Save(Phenix.Core.Security.UserPrincipal.User, MethodBase.GetCurrentMethod(), e.SourceJson);

}

/// <summary>

/// 提交后事件处理函数

/// </summary>

public void SavedEventHandler(SaveEventArgs e)

{

EventLog.Save(Phenix.Core.Security.UserPrincipal.User, MethodBase.GetCurrentMethod(), e.Result.ToString());

}

#endregion

}

插件添加到Host里会自动启动,Plugin对象的Start()函数会被调用到,也就执行了服务端事件的注册方法。插件启动后,可随时被暂停(Plugin对象的Suspend()函数会被调用到)。

服务端事件所传递的参数:

因这些参数都继承了ShallEventArgs,我们可以在XXXing事件里通过将e.Applied设置为true来告知WebAPI数据服务,本事件已自行处理了Fetch或Save操作。这时,事件代码里应该通过给e.Result赋值,将自行处理得到的返回结果传给WebAPI数据服务,WebAPI数据服务会将e.Result内容打包返回给HTTP客户端。

21.1.4案例与建议

测试工程“Phenix.Test.使用指南.21.5”已基本上覆盖了所有可能的数据操作方法,请编译后运行观察效果。

需注意的是,本测试工程在客户端也用到了业务类、实体类,与之相关的配置信息需要被下载到本地。而WebAPI仅提供的是数据操作服务,所以需要额外通过调用Phenixヾ的remoting/WCF服务来下载他们的配置信息:

Phenix.Services.Client.Library.Registration.RegisterWorker(NetConfig.LocalAddress);

在实际开发场景中,客户端如果能够用上remoting/WCF服务的话,就没必要使用WebAPI技术。而一旦使用了WebAPI技术,客户端就没必要用上业务类、实体类。所以,也就不需要上述代码来获取配置信息了。

时间: 2024-08-01 06:34:08

WebAPI 权限控制解决方案——Phenix.NET企业应用软件快速开发平台.使用指南.21.WebAPI服务(三)的相关文章

WebAPI 身份认证解决方案——Phenix.NET企业应用软件快速开发平台.使用指南.21.WebAPI服务(一)

21   WebAPI服务 ASP.NET Web API,是微软在.NET Framework 4.5上推出的轻量级网络服务框架,虽然作为ASP.NET MVC 4的一部分,但却是一套全新的.独立的服务平台开发框架,可支持多种(包括移动)客户端的访问,非常适合于网络平台应用的开发. Phenixヾ在ASP.NET Web API服务框架.及其自身业务框架(封装CSLA)基础上,为跨平台应用系统的实现提供了全面的数据服务,并为服务访问提供了身份认证.权限验证等辅助功能. 21.1   启动服务

企业信息化快速开发平台--JeeSite

JeeSite是在Spring Framework基础上搭建的一个Java基础开发平台,以Spring MVC为模型视图控制器,MyBatis为数据访问层, Apache Shiro为权限授权层,Ehcahe对常用数据进行缓存,Activit为工作流引擎.是JavaEE界的最佳整合. 内置功能 用户管理:用户是系统操作者,该功能主要完成系统用户配置. 机构管理:配置系统组织机构(公司.部门.小组),树结构展现,可随意调整上下级. 区域管理:系统城市区域模型,如:国家.省市.地市.区县的维护. 菜

Phenix.NET for WebAPI &amp; WF &amp; CSLA,企业级、分布式、符合领域建模的OOP软件快速开发平台

2016-8-28版本: Phenix6(for WebAPI & WF & CSLA)开发平台        : http://download.csdn.net/detail/phenixiii/9615312 CSLA & Delphi 爱好者 & Phenix for .net 开发平台用户交流群:206648373 以下是版本升级告示: 在IDE中设计业务类的映射关系演示: 2011-10-9升级: BusinessBase取子业务对象集合时,可以从本地的业务对象

企业采用怎样的快速开发平台好?

企业采用快速开发平台来做信息化管理的话,首先要明确自身的需求,知道自己要什么样的功能,要达到怎样的管理目的,最好是内部动员起来,集思广益:其次在选择快速开发平台的时候,要综合考虑平台的易用性和扩展性,如果应用快速开发平台,还要开发人员再去写代码慢慢把功能堆砌起来,那就太失败了.力软快速开发平台,目前的产品“敏捷开发框架”在易用和扩展性能方面还是值得推荐的, ?? 力软快速开发平台是一款极为好用的快速开发平台,你不需要懂技术,不需要写代码,只需想拼积木一样就可以快速开发出功能强大的管理软件,例如:

Java web自定义标签按钮级别权限控制完美诠释(jplogic 快速开发平台)

接下来跟大家聊聊JavaWeb中权限控制,往大的方向说可以聊聊整合应用系统中的权限控制.在聊权限控制之前先跟大家聊聊RBAC.那么什么是RBAC呢?RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联的,用户通过成为适当角色的成员而得到这些角色的权限.这就极大地简化了权限的管理.在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色.角色可依新的需求和系统的

SNF快速开发平台3.0之--MVC 打印解决方案

SNF-MVC打印报表方案: 报表模块创建的过程如下: 利用Stimulsoft Reports客户端报表工具新增一个报表文件 *.mrt 当然你也可以拿好用的*.mrt模版文件进行复制出来一个,我常用这个方法. 按规定要求放于指定位置:Areas->Sys->Reports->BaseRole.mrt 打开对应的页面功能,点击打印即可,也可以在线编辑报表 第一步:配置打印按钮 第二步:配置打印方法 //打印 this.printClick = function () { snf.ope

开发之南十一:JEECG微云快速开发平台--基础用户权限

 11.1. 权限设计 基本概念 权限管理模块涉及到的实体有:用户.角色和系统资源(包括系统菜单.页面按钮等).用户可以拥有多个角色,角色可以被分配给多个用户.而权限的意思就是对某个资源的某个操作.一般通用的权限管理模块规定:所谓资源即应用系统中提供的要进行鉴权才能访问的资源(比如各类数据,系统菜单):所谓操作即增加.修改.删除.查询等操作. 权限模型 用户权限模型,指的是用来表达用户信息及用户权限信息的数据模型.即能证明"你是谁?"."你能访问哪些受保护资源?"

度量快速开发平台部署IIS服务端后提示不具备查看该目录和页的权限 ALC

今天在云虚拟机上部署度量快速开发平台服务端后,访问效果如下所示:  提示 不具备查看该目录或页面的权限,因为访问控制列表(ALC)对wrb服务器上的该资源进行了配置. 这个错误,主要是IIS上部署的服务端文件夹访问权限不够引起,只需要把服务端目录安全性设置为 network service用户完全控制即可.如果设置这个用户后仍然不行,则需要把everyone用户设置为完全控制才行.原文地址:http://bbs.delit.cn/thread-336-1-1.html 转载请注明出处: 撰写人:

强烈推荐一款搭建企业管理系统的快速开发平台

由于市场不断扩大,销售人员的不断增加以及客户的积累.传统的EXCEL客户拜访表已不能满足现有的需求.因为传统的表单每次数据分析需要将四五十个销售的数据整理成报表需要大量的时间. 公司销售总监交给了我一个任务,想做一个企业客户管理系统便于数据分析,更好地开展工作. 接到这个任务,我有点蒙圈,负责工程中心做云平台开发的同事每天也忙得不可以开交,我去哪里找人来做这个项目. 我知道一个项目至少需要一个团队,没有架构师.没有专业美工,没有前端.什么也没有,怎么开展?好愁呀~~~ 由于市场不断扩大,销售人员