在本文中,将探讨职业生涯中的一个重构项目。由于安全策略的变化,被要求重构现有的WCF服务,以提高它们的安全性和可追溯性。目标是改进现有的服务架构,而不是重写整个服务代码。为了实现这一目标,决定引入授权、认证、日志记录和验证的概念。
最初的想法是重写所有服务,但由于目前使用的服务方法多达数百个,这个想法将带来巨大的开发工作量。因此,决定使用面向方面编程(AOP)来减少开发工作。
在C#中,有几个优秀的AOP库可供使用,如Castle、AspectSharp、Aspect.NET和PostSharp。在这些库中,选择了PostSharp,因为它易于使用,文档完善,并且社区中有大量示例。
使用Microsoft SQL Server来存储数据,并使用Entity Framework进行数据访问。尽管.NET Core可能是一个更现代的方法,但为了减少开发工作,选择使用.NET Framework以保持向后兼容性。
通常,大多数开发者会按照以下方式编写WCF服务:
public interface IExampleService
{
int CreatePlayer(string name, DateTime dateOfBirth, int? height, int? weight, string club);
Player GetPlayerById(int id);
List
第一个行动是将多个输入参数更改为一个包含参数的数据契约类,并按照命名约定,将它们命名为方法名+Request。
[DataContract]
public class CreatePlayerRequest
{
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime DateOfBirth { get; set; }
[DataMember]
public int? Height { get; set; }
[DataMember]
public int? Weight { get; set; }
[DataMember]
public string Club { get; set; }
}
然后为每个特定的服务方法创建响应对象,同样使用命名约定方法名+Response。
[DataContract]
public class CreatePlayerResponse
{
[DataMember]
public int PlayerId { get; set; }
}
当然,可以使用一个Response对象而不是GetAllPlayerResponse和GetClubPlayersResponse对象。
接下来,创建一个名为"WCFServices.Shared"的新类库项目,并将其引用到现有服务中。创建并引用此项目后,让分别创建这两个类。
[DataContract]
public class BaseRequest
{
[DataMember]
public string Username { get; set; }
[DataMember]
public string Password { get; set; }
}
新创建的BaseRequest类将成为所有请求对象的基类,并持有认证和授权所需的信息。类似地,BaseResponse类将成为所有响应对象的基类,并持有所有方法的响应状态信息。
在创建这些类之后,服务中的所有请求和响应类应该更新如下:
[DataContract]
public class CreatePlayerRequest : BaseRequest
{
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime DateOfBirth { get; set; }
[DataMember]
public int? Height { get; set; }
[DataMember]
public int? Weight { get; set; }
[DataMember]
public string Club { get; set; }
}
服务和接口将如下所示:
[ServiceContract]
public interface IExampleService
{
CreatePlayerResponse CreatePlayer(CreatePlayerRequest request);
GetPlayerByIdResponse GetPlayerById(GetPlayerByIdRequest request);
GetAllPlayersResponse GetAllPlayers(BaseRequest request);
GetClubPlayersResponse GetClubPlayers(GetClubPlayersRequest request);
}
public class ExampleService : IExampleService
{
public CreatePlayerResponse CreatePlayer(CreatePlayerRequest request)
{
try
{
return new CreatePlayerResponse
{
PlayerId = PlayerRepository.CreateNewPlayer(request.Name, request.DateOfBirth, request.Height, request.Weight, request.Club),
IsException = false,
IsSuccess = true,
Messages = new string[] { "Operation successful" }
};
}
catch (Exception ex)
{
return new CreatePlayerResponse
{
IsException = true,
IsSuccess = false,
Messages = new string[] { ex.Message; }
};
}
}
public GetAllPlayersResponse GetAllPlayers(BaseRequest request)
{
try
{
return new GetAllPlayersResponse
{
PlayerList = PlayerRepository.GetAllPlayers(),
IsException = false,
IsSuccess = true,
Messages = new string[] { "Operation successful" }
};
}
catch (Exception ex)
{
return new GetAllPlayersResponse
{
IsException = true,
IsSuccess = false,
Messages = new string[] { ex.Message; }
};
}
}
// I think the first two methods give enough clue about the transformation.
// ...
}
这是系列文章的第一部分,解释了更新服务结构的基本方法,并为下一章做准备。