Api ビジネス ロジック プロバイダーとして、プロジェクトのコア ロジックを運ぶため、ロジックの複雑さは比較的高くなります。このような前提のもと、コードの記述をいかに簡素化するか、書き方やロジックの仕様を標準化・統一するか、コードの保守性やスケーラビリティをいかに高めるか。凝集性が高く、結合性が低いプロジェクトを構築することが重要になります。
例はエンタープライズレベルのプロジェクトですフレームワークの図は次のとおりです
セキュリティ: Httpリクエストを書き換え(Override DelegatingHandler)、合法性判定を実行します。リクエストの側面を分析し、署名要件の前処理を実行します。
クライアント: 呼び出し側で使用される統一されたインターフェース呼び出しメソッドを定義し、インターフェースの使用を簡素化し、統一します。
Ctrl 層: サービスの直接プロバイダーとして、RestFul スタイルに似たインターフェイスをサーバー上に直接提供します (厳密な RestFul スタイルには完全なドメイン モデル ドライバー が必要であるように見えますが、実際の状況は常に同じではありません)不十分、ドメイン抽象化機能が不十分)、リクエストデータを取得し、必要に応じて FilterFilter を呼び出し、さらに判断を行って、
Model 層を呼び出します: ビジネス モデル層として、ビジネス ロジックの実際の動作を提供します。 。統合エンティティ モデルを使用し、データ操作のためにそれを Ibatis に接続します。
具体的なコード構造は次のとおりです:
プロジェクトの構造は次のとおりです。
Domainモジュール、エンティティモデルとしての簡単なコードは次のとおりです
public class User { public int Id { get; set; } public string NickName { get; set; } public string Avatar { get; set; } }
Request、リクエスト構造モデルは、汎用インターフェイスを使用してリクエストクラスとリターンを接続します制御反転の役割を果たすクラス。
public abstract class AbstractRequest { public bool ValidateParameters() { //公用方法示例,验证参数合法性 } } public interface IRequest<T> where T:AbstractResponse { //获取接口名称 string GetApiName(); //获取接口编码 string GetApiCode(); } //获取User信息的请求结构定义 public class GetUserRequest:AbstractRequest,IRequest<GetUserResponse> { public int Id { get; set; } public string GetApiName() { return "User.GetUserDetail"; } public string GetApiCode() { return "User001"; } }
Response モジュールは、リクエストの戻りタイプとして、消費者が一貫した戻りコードを判断して処理できるようにするための統一された戻り構造を定義します。
public abstract class AbstractResponse { //返回码 public int Code { get; set; } //报错信息 public string Message { get; set; } } public class GetUserResponse:AbstractResponse { public User User { get; set; } }
プロジェクトの構造は次のとおりです:
コード例:
public interface IUserService { GetUserResponse GetUser(int id); } public class BaseService { //protected SqlInstance sqlInstance; public BaseService() { //sqlInstance=new SqlInstance(); //实例化数据库连接 //... } //... } public class UserService:BaseService,IUserService { public GetUserResponse GetUser(int id) { //链接数据库获取数据 //... throw new NotImplementedException(); } }
クラスライブラリはセキュリティのみを処理しますセキュリティの問題を解決するため、API リクエストエントリに許可判定を追加します。 Httpリクエストを書き換える方法を使用します。
コード例
public class MyHandler : DelegatingHandler { protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { IEnumerable<string> keyEnumerable; var t1 = request.Headers.TryGetValues("key", out keyEnumerable); var key = keyEnumerable.FirstOrDefault(); if (!true)//验证类似于token的权限 { return await Task.Factory.StartNew<HttpResponseMessage>( () => new HttpResponseMessage(HttpStatusCode.Forbidden) { Content = new StringContent("error message") }); } //如果有signature,判断,并加结果标志,没有的话,清除signature相关信息,防止伪造。 //..... return await base.SendAsync(request, cancellationToken); } }
抽象化されたパーミッション判定は、webapi エンドに直接呼び出して、routing設定コードに追加できます。
インターフェースの実際の定義として、webapiはインターフェースファイルの実際のルールを定義し、それに対応するセキュリティ管理とインターフェースの権限制御を行います。 WeChat の権限制御を研究した結果、いくつかのインターフェイスが大まかに特定されました。
これらの権限の判断は、集中管理のためにセキュリティに配置されます。インターフェイス定義は、対応するロジックの正当性を判断するためにのみ使用する必要があります。
コード例:
public class UserController : ApiController { private IUserService userService; public UserController() { userService=new UserService(); } [Signature]//安全签名过滤器判断 [HttpPost] public GetUserResponse GetUser(GetUserRequest request) { //参数判断,安全性判断等等 var ret = userService.GetUser(request.Id); return ret; } }
上記は、インターフェース入口のルーティング設定として、リクエストの正当性を判断するためのサンプルインターフェースです。
public static void Register(HttpConfiguration config) { // Web API configuration and services // Configure Web API to use only bearer token authentication. config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}", defaults: new { id = RouteParameter.Optional } ); //添加的代码,添加http请求的入口处理 config.MessageHandlers.Add(new MyHandler()); }
Client クラス ライブラリは、インターフェイスによって呼び出されるパブリック メソッドを定義します。
1. 汎用インターフェイスを使用してリクエスト クラスと戻りクラスをカプセル化し、呼び出しコードの記述を簡素化します。
2. また、コンシューマがプロキシ クラスを介してインターフェイスを呼び出すことができるため、クロスドメインの問題が回避されます。
3. コンシューマー呼び出しはすべて、統一されたクラス ライブラリの使用に同意します。これにより、統一されたログ処理と返されるエラーも一貫して定義できます。
コード例は次のとおりです:
public interface IClient { T Execute<T>(IRequest<T> request) where T : AbstractResponse; } public class DefaultClient:IClient { private readonly string appKey; private readonly string appSecret; private readonly string baseUrl = "http://localhost:16469/api/"; private readonly bool isNeedLogFile = false; private readonly LogFile logFile; public static readonly string SecureHeaderAppKey = "secure_head_appkey"; public static readonly string SecureHeaderSignature = "secure_head_signature"; public DefaultClient() { baseUrl = ConfigurationManager.AppSettings["service_base_url"]; appKey = ConfigurationManager.AppSettings["app_key"]; appSecret = ConfigurationManager.AppSettings["app_secret"]; isNeedLogFile = "1".Equals(ConfigurationManager.AppSettings["client_log_file"]); logFile = new LogFile("client_log_path"); logFile.SubPath = appKey; } public DefaultClient(string serviceBase, string code, string key) { baseUrl = serviceBase; appKey = code; appSecret = key; } public T Execute<T>(IRequest<T> request) where T : AbstractResponse { var webRequest = (HttpWebRequest)WebRequest.Create(baseUrl + request.GetApiName()); webRequest.Method = "POST"; string reqJson; string sign; using (Stream rs = webRequest.GetRequestStream()) { reqJson = JsonConvert.SerializeObject(request); byte[] reqBytes = Encoding.UTF8.GetBytes(reqJson); rs.Write(reqBytes, 0, reqBytes.Length); rs.Close(); } webRequest.ContentType = "application/json"; webRequest.Headers.Add(SecureHeaderAppKey, appKey); sign = ComputeHash(appKey, appSecret, reqJson); webRequest.Headers.Add(SecureHeaderSignature, sign); //记录日志 if (isNeedLogFile) { logFile.Log(string.Format("[{0}] 请求内容: {1}", request.GetApiCode(), reqJson)); logFile.Log(string.Format("[{0}] 请求签名: {1}", request.GetApiCode(), sign)); } try { using (var resp = (HttpWebResponse)webRequest.GetResponse()) { try { Stream respStream = resp.GetResponseStream(); if (respStream == null) { throw new WebException("GetResponseStream returned null"); } var streamReader = new StreamReader(respStream); string respStr = streamReader.ReadToEnd(); //记录日志 if (isNeedLogFile) { logFile.Log(string.Format("[{0}] 响应内容: {1}", request.GetApiCode(), respStr)); } return JsonConvert.DeserializeObject<T>(respStr); } catch (Exception e) { //记录日志 if (isNeedLogFile) { logFile.Log(string.Format("[{0}] 响应错误: {1}", request.GetApiCode(), e.Message)); } throw new ApplicationException(e.Message, e); } } } catch (WebException e) { var errMsg = new StreamReader(e.Response.GetResponseStream()).ReadToEnd(); //记录日志 if (isNeedLogFile) { logFile.Log(string.Format("[{0}] 请求错误: {1}", request.GetApiCode(), errMsg)); } throw new APIServiceException(errMsg); } } private string ComputeHash(string key, string secret, string body) { return Convert.ToBase64String( SHA1.Create().ComputeHash(Encoding.Default.GetBytes(string.Concat(key, secret, body.Trim())))); } }
以上就是Api项目端的各个核心环节的详细介绍。
接下来会对调用端即前端进行简单的介绍。Asp.net(三)Web端展示
以上がAsp.net (2) 業務処理インターフェースプロジェクト(Web API)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。