タイトルママ。
Jsonの型がころころ変わっても対応できるように作ろうとしたらこんな感じになった。
力尽きてるので努力したということだけ残しておきたい。
継承先クラスにて抽象メソッドExecute()内部に実施する処理を実装、
継承先ではルート設定したメソッドからAsyncCreateResponseData()をコールすれば動く。
もうちょっとお手軽にしたかったナー。
BaseApiController.cs
using System;
using System.IO;
using System.Text;
using System.Net.Http.Headers;
using System.Collections.Generic;
using System.Web.Http;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using ***.WebApi.Model;
using ***.WebApi.Common;
using System.Threading.Tasks;
namespace ***.WebApi.Controller
{
#region *** Jsonデータ保持用Publicクラス ***
public class CodeNameObject
{
public string Code = null;
public string Name = null;
}
/// <summary>
/// Httpリクエスト情報保持クラス
/// </summary>
/// <typeparam name="T">RequestKey型</typeparam>
public class ModelRequest<T> where T : BaseApiController.BaseRequestKeys
{
public T data;
public string token = "";
}
/// <summary>
/// Httpレスポンス情報保持クラス
/// </summary>
/// <typeparam name="T">ResponseKey型</typeparam>
public class ModelResponse<T> where T : BaseApiController.BaseResponseKeys
{
public string resultCode = Common.resultCode.Error_Fatal;
public object validationMessage = null;
public T data;
public string message = CommonStrings.DataBase.Fatal.NeverSetMessage;
public string token = "";
}
#endregion
#region *** BaseApiControllerクラス ***
/// <summary>
/// /WebAPI用の基底クラスです。
/// </summary>
#if !DEBUG
[Authorize]
#endif
public abstract class BaseApiController : ApiController
{
#region *** 内部変数 ***
/// <summary>
/// DBエンティティモデルクラス
/// </summary>
protected static ***Entities db;
/// <summary>
/// ロガー設定クラス
/// </summary>
protected static NLog.Logger logger;
private object _ResponseData;
#endregion
#region *** プロパティ ***
protected object ResponseData
{
get { return _ResponseData; }
}
#endregion
#region *** 基底クラス ***
/// <summary>
/// Httpリクエスト展開用基底クラス
/// </summary>
public abstract class BaseRequestKeys
{
}
/// <summary>
/// Httpレスポンス展開用基底クラス
/// </summary>
public abstract class BaseResponseKeys
{
}
#endregion
#region *** コンストラクタ ***
protected BaseApiController()
{
if (db == null)
{
db = new ***Entities();
db.Configuration.LazyLoadingEnabled = false; // 遅延書き込み禁止
db.Configuration.ProxyCreationEnabled = false; // 動的プロキシ禁止
}
if (logger == null)
{
logger = NLog.LogManager.GetCurrentClassLogger();
}
}
#endregion
#region *** protected メソッド ***
#region *** Json変換メソッド ***
/// <summary>
/// エンティティクラスをHttpResponceのJsonデータに変換します。
/// </summary>
/// <param name="obj">変換元データ</param>
/// <returns></returns>
protected HttpResponseMessage SerializeJson(dynamic obj)
{
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
return response;
}
/// <summary>
/// HttpリクエストのJsonデータをエンティティクラスに変換します。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns></returns>
protected dynamic DeserializeJson<T>(HttpRequestMessage request) where T : BaseRequestKeys
{
string jsonString = request.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<ModelRequest<T>>(jsonString); ;
}
#endregion
#region *** 認証用 ***
/// <summary>
/// ワンタイムトークンを発行します
/// </summary>
/// <returns></returns>
protected string GenerateToken()
{
return "";
}
/// <summary>
/// トークンが正規であるか否かを判定します。
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
protected bool IsAuthrizeToken(string token)
{
return true;
}
#endregion
#region *** ユーリティ関数 ***
/// <summary>
/// 空の配列を取得します。
/// </summary>
/// <returns></returns>
protected System.Collections.Generic.List<string> GetBlank()
{
return new List<string>();
}
protected ModelResponse<T> InitializeResponseKey<T>() where T:BaseResponseKeys, new()
{
ModelResponse<T> ret = new ModelResponse<T>();
ret.data = new T();
return ret;
}
#endregion
#region *** 実処理 ***
/// <summary>
/// Httpレスポンスデータを作成します。
/// </summary>
/// <typeparam name="T1">ResponseKeyクラス</typeparam>
/// <typeparam name="T2">RequestKeyクラス</typeparam>
/// <param name="request">Httpリクエストデータ</param>
/// <returns>Httpレスポンスデータ</returns>
/// <remarks>トランザクションは使用しません。使用する場合はオーバーロードの第二引数にtrueを設定してください。</remarks>
protected Task AsyncCreateResponseData<T1, T2>(HttpRequestMessage request) where T1 : BaseResponseKeys where T2 : BaseRequestKeys
{
return Task.Run(() =>
{
_ResponseData = CreateResponseData<T1, T2>(request, false);
});
}
/// <summary>
/// Httpレスポンスデータを作成します。
/// </summary>
/// <typeparam name="T1">ResponseKeyクラス</typeparam>
/// <typeparam name="T2">RequestKeyクラス</typeparam>
/// <param name="request">Httpリクエストデータ</param>
/// <param name="IsUseTransaction">true:トランザクション使用 false:トランザクション不使用</param>
/// <returns>Httpレスポンスデータ</returns>
protected Task AsyncCreateResponseData<T1, T2>(HttpRequestMessage request, bool IsUseTransaction) where T1 : BaseResponseKeys where T2 : BaseRequestKeys
{
return Task.Run(() =>
{
_ResponseData = CreateResponseData<T1, T2>(request, IsUseTransaction);
});
}
/// <summary>
/// Httpレスポンスデータを作成します。
/// </summary>
/// <typeparam name="T1">ResponseKeyクラス</typeparam>
/// <typeparam name="T2">RequestKeyクラス</typeparam>
/// <param name="request">Httpリクエストデータ</param>
/// <param name="IsUseTransaction">true:トランザクション使用 false:トランザクション不使用</param>
/// <returns>Httpレスポンスデータ</returns>
private ModelResponse<T1> CreateResponseData<T1, T2>(HttpRequestMessage request, bool IsUseTransaction)
where T1 : BaseResponseKeys
where T2 : BaseRequestKeys
{
// 戻り値生成
ModelResponse<T1> ret = new ModelResponse<T1>();
// トークンの設定
ret.token = this.GenerateToken();
//検索用パラメータの取得
ModelRequest<T2> req = (ModelRequest<T2>)DeserializeJson<T2>(request);
try
{
// 検証
if(req != null){
object Checker = null;
ret.message = CheckValidate(req.data, out Checker);
if (ret.message != string.Empty)
{
// 検証失敗時
ret.resultCode = resultCode.Select_WithInfo;
ret = (ModelResponse<T1>)Checker;
return ret;
}
}
// 処理実行
{
object Records = null;
int ResultCodeOrSelectCount = 0;
// トランザクションを使用する場合
if (IsUseTransaction)
{
using (var tran = db.Database.BeginTransaction())
{
try
{
ResultCodeOrSelectCount = Execute(req.data, out Records);
// 更新実行
if (this.SaveChanges())
{
//更新正常終了
tran.Commit();
ResultCodeOrSelectCount = DBParameters.ResultCode.UpdateSuccess;
}
else
{
//更新失敗(検証失敗、検証以外は例外をスロー)
tran.Rollback();
ResultCodeOrSelectCount = DBParameters.ResultCode.UpdateValidateError;
}
}
catch (Exception ex)
{
// 検証以外の例外時は例外を再スロー
tran.Rollback();
throw ex;
}
}
}
else
{
ResultCodeOrSelectCount = Execute(req.data, out Records);
}
// 取得レコードが存在する場合、レスポンスデータに設定
if (Records != null)
{
logger.Info("");
ret = (ModelResponse<T1>)Records;
}
// 戻り値の設定
{
// 返却メッセージ初期化
ret.message = CommonStrings.DataBase.EmptyMessage;
// 戻り値によって返却値、メッセージを設定
switch (ResultCodeOrSelectCount)
{
case DBParameters.Parameter.SelectMin:
ret.resultCode = resultCode.Select_NotFoundResult;
ret.message = CommonStrings.DataBase.Warning.Select_RecordNotExist;
break;
case DBParameters.Parameter.SelectMax:
ret.resultCode = resultCode.Select_WithInfo;
ret.message = CommonStrings.DataBase.Question.Select_OverRecords;
break;
case DBParameters.ResultCode.UpdateSuccess:
ret.resultCode = resultCode.Update_Success;
break;
case DBParameters.ResultCode.UpdateValidateError:
ret.resultCode = resultCode.Update_WithWarinig;
break;
default:
ret.resultCode = resultCode.Select_Success;
break;
}
}
}
}
catch (Exception ex)
{
logger.Fatal(ex.Message);
ret.resultCode = resultCode.Error_Fatal;
ret.message = ex.Message;
}
return ret;
}
#endregion
#region *** DB更新 ***
/// <summary>
/// EntityFrameworkの更新情報を確定します。
/// </summary>
protected bool SaveChanges()
{
bool ret = false;
try
{
//db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
return true;
}
catch (System.Data.Entity.Infrastructure.DbUpdateConcurrencyException ex)
{
// オプティミスティック同時実行制御違反
logger.Fatal(ex.Message);
throw ex;
}
catch (System.Data.Entity.Infrastructure.DbUpdateException ex)
{
// データベースへの更新送信エラー
logger.Fatal(ex.Message);
throw ex;
}
catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
// エンティティ検証エラー
foreach (var errors in ex.EntityValidationErrors)
{
foreach (var error in errors.ValidationErrors)
{
//ログ出力
logger.Fatal(error.ErrorMessage);
}
}
}
catch (NotSupportedException ex)
{
// 非サポートコマンド実施
logger.Fatal(ex.Message);
throw ex;
}
catch (ObjectDisposedException ex)
{
// コンテキスト破棄エラー
logger.Fatal(ex.Message);
throw ex;
}
catch (InvalidOperationException ex)
{
// コマンド送信時コンテキスト内部処理エラー
logger.Fatal(ex.Message);
throw ex;
}
catch (Exception ex)
{
logger.Fatal(ex.Message);
throw ex;
}
logger.Fatal(System.Reflection.MethodBase.GetCurrentMethod().Name);
return ret;
}
#endregion
#region *** Pdf返却 ***
/// <summary>
/// Pdfを作成、ストリームとして返却します。
/// </summary>
/// <param name="openFilePath"></param>
/// <param name="returnFileName"></param>
/// <returns></returns>
protected HttpResponseMessage GetHttpResponseMessageByPdf(string openFilePath, string returnFileName)
{
// 作成したファイルをストリーム送信用に変換
HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(openFilePath, FileMode.Open));
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = returnFileName;
return result;
}
#endregion
#endregion
#region*** 抽象メソッド ***
/// <summary>
/// 入力値の検証結果を取得します。
/// </summary>
/// <param name="objRequestKeys">検索条件</param>
/// <param name="objRecords">(out)検索結果</param>
/// <returns>空文字:検証OK 空文字以外:異常内容の説明文字列</returns>
/// <remarks>検証が必要な場合のみオーバーライドして定義されます。</remarks>
protected virtual string CheckValidate(object RequestKeys, out object records)
{
records = null;
return string.Empty;
}
/// <summary>
/// 要求された処理を実行します。
/// </summary>
/// <param name="objRequestKeys">検索条件</param>
/// <param name="objRecords">(out)検索結果</param>
/// <returns>処理結果 検索時:レコード件数 / 更新時処理:結果</returns>
protected abstract int Execute(object objRequestKeys, out object records);
#endregion
}
#endregion
}