预备知识:
asp.net下的webapi网站项目的一定了解
程序开发中条件编译的概念 以及 Visual Studio项目中条件编译的用法
理解这两个基本知识即可。
问题描述:
现在我们有一个webapi站点(简单点,就拿VS自带的框架生成一个默认的),显然地,运行此webapi站点,会得到这样的一个网站,此时网站首页如图1,help页如图2,图3.
这几个页面的含义应该不用太多介绍,总之就是列出接口名称、参数形式、返回值形式、请求示例这样的,便于开发者参考而已。
至于真实的接口地址,则是类似于 http://xxx.com/api/MemberBusinessModel/method1?key={key} 这样的形式。
以上是基本常识,都很容易理解。
现在问题来了,在开发时,我们当然希望如上3图中的信息能够看到,这样在开发中可以省去很多不必要的沟通,调用者直接看帮助页列出的接口列表,然后直接调用即可。
但是当要部署到生产环境时,有时我们不希望别人能够看到这些接口列表等信息,希望访问帮助页的时候服务器能够区分,然后直接重定向到404页面等。
这要怎么办呢?
-----------
为了解决这个问题,想过几种方法,简单描述:
1. 写一套验证授权机制(此方法成本最大,也最蠢)。
访问这些页面时有登录等行为,用户名和密码测试环境的我们自己知道。线上别人访问的话就不知道,也就无法登录,也就无法看到接口列表等信息。
具体实现不说了,意义不大。
2. 投机一点,行之有效,简单粗暴的办法(最容易理解,最容易实现)
将如下图所示的Areas文件夹右键选中,排除出项目,然后编译。这里面是帮助页相关的信息,与api接口调用并无关系,因此不会出问题。
但当试图访问帮助页时,显然都是看不到的,能看到的只是一个粗暴的报错页。
当然,如果觉得这个页面太不友好,那就发挥编码精神,将这样的错误页在web.config页面中,甚至在Controller中的Method的return view的时候指定到自己想要指定的页面,如自己写的404.html页面。
这样最容易理解,但问题就是测试环境和生产环境的代码其实已经不同的,至少有help中的HelpController.cs文件、HomeController.cs文件,.csproj文件等几处不同,总感觉有些不太好。
而且如果发布的时候用的依然是这份代码,难道还要再用vs打开,然后排除出项目,然后编译?这多麻烦。
结论:简单粗暴,易于理解,但测试环境与生产环境代码不一致,不是很好。
3. 通过条件编译的思路实现,稍有门槛,一劳永逸。
这也就是本文犹抱琵琶半遮面的内容。
- 重写http过滤器/拦截器什么的,拦截每一个发来的请求,如对api接口的请求,对help页面的访问请求等所有的
- 将此过滤器应用到HomeController的class或method上,应用到help页面的class上。
- 指定条件编译内容
- 从此即可保持代码一致。
- 重写一个拦截器,随便放项目的什么地方,
using System.Web.Mvc;
namespace webApi.Util
{
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
//如果是在!testV条件下,则将一切请求(指的是应用了CustomAuthorize的控制器class或method)直接重定向到404页面;反之,执行默认行为
#if !testV
filterContext.Result = new RedirectResult("~/404.html");
#endif
}
}
}
2.分别将此拦截器应用到HomeController.cs上和HelpControlle.cs上。
using System.Web.Mvc;
using webApi.Util;
namespace webApi.Controllers
{
/// <summary>
///
/// </summary>
public class HomeController : Controller
{
/// <summary>
///
/// </summary>
/// <returns></returns>
[CustomAuthorize]
public ActionResult Index()
{
return View();
}
}
}
using System;
using System.Web.Http;
using System.Web.Mvc;
using webApi.Areas.HelpPage.Models;
using webApi.Util;
namespace webApi.Areas.HelpPage.Controllers
{
/// <summary>
/// The controller that will handle requests for the help page.
/// </summary>
[CustomAuthorize]
public class HelpController : Controller
{
//略
}
}
3.如果help页面不需要了,则bundile.cs里的很多文件处理也不需要了的,也应该处理一下。
BundleConfig.cs
using System.Web;
using System.Web.Optimization;
namespace webApi
{
public class BundleConfig
{
// 有关 Bundling 的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=254725
public static void RegisterBundles(BundleCollection bundles)
{
//如果是在testV条件下,则执行这些bundles行为;如果不是testV,则相当于这部分代码就不存在
#if testV
bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/OriginalJs/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include("~/Scripts/OriginalJs/jquery-ui-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include("~/Scripts/OriginalJs/jquery.unobtrusive*", "~/Scripts/OriginalJs/jquery.validate*"));
// 略
#endif
}
}
}
4.执行条件编译即可。
如下图,显然地,testV适用于测试环境,没有testV适用于生产环境。
如上图即完美完成。