Maven-No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? [INFO] Scanning for projects… [INFO] [INFO] ———————————————————————— [INFO] Building helloworld 0.0.1-SNAPSHOT [INFO] ———————————————————————— [INFO] [INFO] — maven-clean-plugin:2.5:clean (default-clean) @ helloworld — [INFO] Deleting H:\mavenok\helloworld\target [INFO] [INFO] — maven-resources-plugin:2.6:resources (default-resources) @ helloworld — [INFO] Using ‘UTF-8‘ encoding to copy filtered resources. [INFO] skip non existing resourceDirectory H:\mavenok\helloworld\src\main\resources [INFO] [INFO] — maven-compiler-plugin:3.1:compile (default-compile) @ helloworld — [INFO] Changes detected – recompiling the module! [INFO] Compiling 1 source file to H:\mavenok\helloworld\target\classes [INFO] ————————————————————- […]
View Details提示信息应该能看懂。也就是缺少了web.xml文件,<failOnMissingWebXml>被设置成true了。 搜索了一下,Stack Overflow上的答案解决了问题,分享一下。 目前被顶次数最多的回答原文如下: This is a maven error. It says that it is expecting a web.xml file in your project because it is a web application, as indicated by <packaging>war</packaging>. However, for recent web applications a web.xml file is totally optional. Maven needs to catch up to this convention. Add this to your maven pom.xml to let maven catch up and you don’t need to add a useless web.xml to your project: 大意是说这是一个Maven错误,在最近的web应用开发中web.xml文件已经变得可有可无了。不过Maven还没有跟上这一变化,我们只要在pom.xml文件中手动添加如下配置:
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="tag"><build></span> <span class="tag"><plugins></span> <span class="tag"><plugin></span> <span class="tag"><groupId></span><span class="pln">org.apache.maven.plugins</span><span class="tag"></groupId></span> <span class="tag"><artifactId></span><span class="pln">maven-war-plugin</span><span class="tag"></artifactId></span> <span class="tag"><version></span><span class="pln">2.6</span><span class="tag"></version></span> <span class="tag"><configuration></span> <span class="tag"><failOnMissingWebXml></span><span class="pln">false</span><span class="tag"></failOnMissingWebXml></span> <span class="tag"></configuration></span> <span class="tag"></plugin></span> <span class="tag"></plugins></span> <span class="tag"></build></span> |
“告知”maven即可。这样做的好处是我们不必在项目生中成一个无用的web.xml文件。在更新版本(具体从哪一个版本开始我也不知道~~)的maven中已经不存在web.xml文件缺失的问题,我们只需要处理<failOnMissingWebXml>被设置成tue的问题即可。也就是在pom.xml中添加如下配置即可。
1 2 3 |
<span class="tag"><properties></span> <span class="tag"><failOnMissingWebXml></span><span class="pln">false</span><span class="tag"></failOnMissingWebXml></span> <span class="tag"></properties></span> |
其他方案:(生成web.xml——>部署运行时文件路径) you can do it also like this: Right click on Deployment Descriptor in Project Explorer. Select Generate Deployment Descriptor […]
View DetailsSpring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。 特点 1. 创建独立的Spring应用程序 2. 嵌入的Tomcat,无需部署WAR文件 3. 简化Maven配置 4. 自动配置Spring 5. 提供生产就绪型功能,如指标,健康检查和外部配置 6. 绝对没有代码生成和对XML没有要求配置
View Details什么是KT库? KT它是一个免费的、开源的(采用LGPL开源协议)函数库。它是Kingthy的个人开发库,它也可以算是一个小的开发框架包。 KT里包含有什么? KT.Core KT库的核心函数存放地方 KT.Core.Data 目前只有一个CSVTextReader对象,用于处理CSV格式的文本数据 KT.Core.Extensions 存放各种类型数据的相关扩展方法 KT.Core.Net 存放处理与网络有关的对象 KT.Core.Net.Mail 存放处理与电子邮件相关的数据对象 KT.Core.ObjectPool 存放与对象池相关的数据对象 KT.Framework KT库的简易开发框架 KT.Framework.Database 存放的是与数据库有关的已封装的数据对象 KT.Framework.Web 存放的是基于VTemplate模板引擎的Web框架封装 KT的使用环境是什么? 运行环境:.NET 4.0 开发环境:VS2010 我在哪里可以下载获取到最新的KT代码? KT目前采用托管于CodePlex开源网站,所以你可以从以下网址获取最新版本的KT库 项目地址:http://kt.codeplex.com/ from:http://www.cnblogs.com/kingthy/archive/2011/08/08/2130973.html
View DetailsGroovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy 可以使用其他 Java 语言编写的库。 Groovy 是 用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。 Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。
View Details阅读目录 一、get请求 1、基础类型参数 2、实体作为参数 3、数组作为参数 4、“怪异”的get请求 二、post请求 1、基础类型参数 2、实体作为参数 3、数组作为参数 4、后台发送请求参数的传递 三、put请求 1、基础类型参数 2、实体作为参数 3、数组作为参数 四、delete请求 五、总结 正文 前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料。如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路。本篇针对初初使用WebApi的同学们,比较基础,有兴趣的且看看。 WebApi系列文章 C#进阶系列——WebApi接口测试工具:WebApiTestClient C#进阶系列——WebApi 跨域问题解决方案:CORS C#进阶系列——WebApi身份认证解决方案:Basic基础认证 C#进阶系列——WebApi接口传参不再困惑:传参详解 C#进阶系列——WebApi接口返回值不困惑:返回值类型详解 C#进阶系列——WebApi异常处理解决方案 C#进阶系列——WebApi区域Area使用小结 本篇打算通过get、post、put、delete四种请求方式分别谈谈基础类型(包括int/string/datetime等)、实体、数组等类型的参数如何传递。 一、get请求 对于取数据,我们使用最多的应该就是get请求了吧。下面通过几个示例看看我们的get请求参数传递。 1、基础类型参数
1 2 3 4 5 |
[HttpGet] public string GetAllChargingData(int id, string name) { return "ChargingData" + id; } |
1 2 3 4 5 6 7 8 9 10 |
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetAllChargingData", data: { id: 1, name: "Jim", bir: "1988-09-11"}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } }); |
参数截图效果 这是get请求最基础的参数传递方式,没什么特别好说的。 2、实体作为参数 如果我们在get请求时想将实体对象做参数直接传递到后台,是否可行呢?我们来看看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class TB_CHARGING { /// <summary> /// 主键Id /// </summary> public string ID { get; set; } /// <summary> /// 充电设备名称 /// </summary> public string NAME { get; set; } /// <summary> /// 充电设备描述 /// </summary> public string DES { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime CREATETIME { get; set; } } |
1 2 3 4 5 |
[HttpGet] public string GetByModel(TB_CHARGING oData) { return "ChargingData" + oData.ID; } |
1 2 3 4 5 6 7 8 9 10 11 |
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetByModel", contentType: "application/json", data: { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } }); |
测试结果 由上图可知,在get请求时,我们直接将json对象当做实体传递后台,后台是接收不到的。这是为什么呢?我们来看看对应的http请求 原来,get请求的时候,默认是将参数全部放到了url里面直接以string的形式传递的,后台自然接不到了。 原因分析:还记得有面试题问过get和post请求的区别吗?其中有一个区别就是get请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),而post请求则是放在http协议包的包体中。 根据园友们的提议,Get请求的时候可以在参数里面加上[FromUri]即可直接得到对象。还是贴上代码:
1 2 3 4 5 6 7 |
var postdata = { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }; $.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetAllChargingData", data: postdata, success: function (data, status) { } }); |
1 2 3 4 5 |
[HttpGet] public string GetAllChargingData([FromUri]TB_CHARGING obj) { return "ChargingData" + obj.ID; } |
得到结果: 如果你不想使用[FromUri]这些在参数里面加特性的这种“怪异”写法,也可以采用先序列化,再在后台反序列的方式。
1 2 3 4 5 6 7 8 9 10 11 |
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetByModel", contentType: "application/json", data: { strQuery: JSON.stringify({ ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }) }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } }); |
1 2 3 4 5 6 |
[HttpGet] public string GetByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; } |
这样在后台得到我们序列化过的对象,再通过反序列化就能得到对象。 在url里面我们可以看到它自动给对象加了一个编码: 至于还有园友们提到http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api的model binder这种方式,博主看了下,觉得略复杂。有兴趣的也可以试试。至于用哪一种方式传递对象,园友们可以自行选择。 3、数组作为参数 一般get请求不建议将数组作为参数,因为我们知道get请求传递参数的大小是有限制的,最大1024字节,数组里面内容较多时,将其作为参数传递可能会发生参数超限丢失的情况。 4、“怪异”的get请求 为什么会说get请求“怪异”呢?我们先来看看下面的两种写法对比。 (1)WebApi的方法名称以get开头
1 2 3 4 5 6 7 8 9 10 11 |
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetByModel", contentType: "application/json", data: { strQuery: JSON.stringify({ ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }) }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } }); |
1 2 3 4 5 6 |
[HttpGet] public string GetByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; } |
这是标准写法,后台加[HttpGet],参数正常得到: 为了对比,我将[HttpGet]去掉,然后再调用
1 2 3 4 5 6 |
//[HttpGet] public string GetByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; } |
貌似没有任何问题!有人就想,那是否所有的get请求都可以省略掉[HttpGet]这个标注呢。我们试试便知。 (2)WebApi的方法名称不以get开头 我们把之前的方法名由GetByModel改成FindByModel,这个再正常不过了,很多人查询就不想用Get开头,还有直接用Query开头的。这个有什么关系吗?有没有关系,我们以事实说话。
1 2 3 4 5 6 7 8 9 10 11 |
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/FindByModel", contentType: "application/json", data: { strQuery: JSON.stringify({ ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }) }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } }); |
1 2 3 4 5 6 |
[HttpGet] public string FindByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; } |
貌似又可行,没有任何问题啊。根据上面的推论,我们去掉[HttpGet]也是可行的,好,我们注释掉[HttpGet],运行起来试试。 结果是不进断点,有些人不信,我们在浏览器里面看看http请求: 呵呵,这就奇怪了,就改了个方法名,至于这样么?还真至于! 博主的理解是:方法名以Get开头,WebApi会自动默认这个请求就是get请求,而如果你以其他名称开头而又不标注方法的请求方式,那么这个时候服务器虽然找到了这个方法,但是由于请求方式不确定,所以直接返回给你405——方法不被允许的错误。 最后结论:所有的WebApi方法最好是加上请求的方式([HttpGet]/[HttpPost]/[HttpPut]/[HttpDelete]),不要偷懒,这样既能防止类似的错误,也有利于方法的维护,别人一看就知道这个方法是什么请求。 这也就是为什么很多人在园子里面问道为什么方法名不加[HttpGet]就调用不到的原因! 二、post请求 在WebApi的RESETful风格里面,API服务的增删改查,分别对应着http的post/delete/put/get请求。我们下面就来说说post请求参数的传递方式。 1、基础类型参数 post请求的基础类型的参数和get请求有点不一样,我们知道get请求的参数是通过url来传递的,而post请求则是通过http的请求体中传过来的,WebApi的post请求也需要从http的请求体里面去取参数。 (1)错误的写法
1 2 3 4 5 6 7 8 9 10 |
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", data: { NAME: "Jim" }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } }); |
1 2 3 4 5 |
[HttpPost] public bool SaveData(string NAME) { return true; } |
这是一种看上去非常正确的写法,可是实际情况是: (2)正确的用法
1 2 3 4 5 6 |
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", data: { "": "Jim" }, success: function (data, status) {} }); |
[…]
View Details一、路由介绍 ASP.NET Web API路由是整个API的入口。我们访问某个资源就是通过路由映射找到对应资源的URL。通过URL来获取资源的。 对于ASP.NET Web API内部实现来讲,我们的请求最终将定位到一个具体的Action上。所以说,ASP.NET Web API路由就是把客户端请求映射到对应的Action上的过程。 二、两种路由模式 2.1 模板路由 模板路由是ASP.NET Web API默认提供的路由。下面我们就简单讲解此中路由的用法。 默认模板路由 模板路由使用前需要定义路由模板。如下面默认的路由模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace Supernova.Webapi { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } } |
此模板路由是新建项目默认生成的,在App_Start文件夹下。 我们可以看到此模板的URL格式是api/{controller}/{id}。api代表在资源前面要带上api目录,controller代表请求资源的控制器名称。id代表一条资源的id,id 是可选的。这种默认的模板是不带action的,所以它是以请求方式来区分资源的,我们必须在action上添加请求方式特性加以区分。 1.我们添加一个测试控制器api。
1 2 3 4 5 6 7 |
public class TestController : ApiController { public object Get1() { return "d1"; } } |
用fiddldr调试如下: 2.我们添加两个方法如下:
1 2 3 4 5 6 7 8 9 10 11 |
public class TestController : ApiController { public object Get1() { return "d1"; } public object Get2() { return "d2"; } } |
我们再用fiddler调试如下: 错误信息是: {"Message":"出现错误。","ExceptionMessage":"找到了与该请求匹配的多个操作: \r\n类型 Supernova.Webapi.Controllers.TestController 的 Get1\r\n类型 Supernova.Webapi.Controllers.TestController 的 Get2","ExceptionType":"System.InvalidOperationException","StackTrace":" 在 System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n 在 System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"} 我们将代码改为如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class TestController : ApiController { public object Get1() { return "d1"; } [HttpPost] public object Get2() { return "d2"; } } |
调试返回Get1的信息。 从上面两个测试我们可以得出如下结论: action的默认请求方式是HttpGet。 当多个action的 请求方式一样的话,在默认路由模板下(没有action),将会匹配多个操作。 基于上面两点结论,默认路由模板无法满足针对一种资源一种请求方式的多种操作(比如修改操作,可能针对不同的字段进行修改)。 定制模板路由 我们重新定制模板路由,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace Supernova.Webapi { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } } |
从上面我们可以看出,在默认路由的基础上,我们队路由模板增加了一级action。 测试api如下:
1 2 3 4 5 6 7 8 9 10 11 |
public class TestController : ApiController { public object Get1() { return "d1"; } public object Get2() { return "d2"; } } |
我们再通过http://192.168.0.230/api/test访问,返回404,如图: 我们通过http://192.168.0.230/api/test/Get1访问,结果正确,如图: 我们通过http://192.168.0.230/api/test/Get2访问,结果正确,如图: 通过定制路由模板我们可以得出如下结论: 通过在路由模板中增加action目录,对资源的定位直接作用到action上。 多个HttpGet方法可以共存于一个controller中。 基于上面两点结论,通过修改路由模板可以满足针对一种资源一种请求方式的多种操作。 2.2 特性路由 特性路由是通过给action打attribute的方式定义路由规则。 有时候我们会有这样的需求,我们请求的一个资源带有子资源。比如文章评论这样有关联关系的资源。我们希望通过如下URL获得某篇文章下的所有评论:api/book/id/comments。而仅仅凭借模板路由很难实现这种路由模式。这时候我们就需要特性路由来解决这个问题了。ASP.NET Web API为我们准备了Route特性,该特性可以直接打到Action上,使用非常灵活、直观。 下面我将先简单的介绍特性路由的使用方法。 我们重新定义api如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class TestController : ApiController { [Route("demo")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/get")] [HttpGet] public object Get2() { return "d2"; } } |
[…]
View DetailsHttpWebRequest POST请求webapi:如果参数是简单类型,比如字符串(注意,拼接的字符串要HttpUtility.UrlEncode才行,否则服务端会丢失特殊字符&后面的数据) 要点:如下代码统一设置为:ContentType = "application/x-www-form-urlencoded"; 服务端代码1:URL格式为 POSTapi/Values public string Post([FromBody] string value) 则客户端Post的数据:拼接的字符串必须以 =开头,否则服务端无法取得value。例如:=rfwreewr2332322232 或者 {":value} 服务端代码2:URL格式为 POST api/Values?value={value} public string Post(string value) 则客户端Post的数据:需要url里拼接出KeyValue这样的数据 服务端代码3:URL格式为 POST api/Values public string Post() 则客户端Post的数据:无要求。例如:key=rfwreewr2332322232。 服务端:可以用HttpContext.Current.Request.InputStream或者HttpContext.Current.Request.Form[0]都可以获取 如果post的参数类型比较复杂,则需要自定义类 要点:如下代码统一设置为:ContentType = "application/json"; 服务端代码1:URL格式为 POST api/Values public string Post([FromBody] Model value)或者 public string Post(Model value) 则客户端Post的数据:{\"id\":\"test1\",\"name\":\"value\"}。服务端会自动映射到对象。 提交代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
HttpWebRequest wReq = (HttpWebRequest)WebRequest.Create("http://localhost:37831/api/Values"); wReq.Method = "Post"; //wReq.ContentType = "application/json"; //wReq.ContentType = "application/x-www-form-urlencoded"; wReq.ContentType = "application/json"; //byte[] data = Encoding.Default.GetBytes(HttpUtility.UrlEncode("key=rfwreewr2332322232&261=3&261=4")); byte[] data = Encoding.Default.GetBytes("{\"id\":\"test1\",\"name\":\"value\"}"); wReq.ContentLength = data.Length; Stream reqStream = wReq.GetRequestStream(); reqStream.Write(data, 0, data.Length); reqStream.Close(); using (StreamReader sr = new StreamReader(wReq.GetResponse().GetResponseStream())) { string result = sr.ReadToEnd(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// POST api/values //public string Post() //{ // FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log.txt"); // StreamWriter sw = fi.CreateText(); // StreamReader sr = new StreamReader(HttpContext.Current.Request.InputStream); // sw.WriteLine("1:" + sr.ReadToEnd()+"--"+ HttpContext.Current.Request.Form[0]); // sw.Flush(); // sw.Close(); // return "{\"test\":\"1\"}"; //} // POST api/values public HttpResponseMessage PostStudent(Student student) { FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log.txt"); StreamWriter sw = fi.AppendText(); sw.WriteLine("2:" + student.id); sw.Flush(); sw.Close(); HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent("{\"test\":\"2\"}", Encoding.GetEncoding("UTF-8"), "application/json") }; return result; } |
这篇文章里有的方法也不错:http://www.cnblogs.com/rohelm/p/3207430.html from:http://blog.csdn.net/wyqlxy/article/details/49303345
View Details
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
using System; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Security; namespace OtherApi.Auth { public class AuthFilterOutside : AuthorizeAttribute { //重写基类的验证方式,加入我们自定义的Ticket验证 public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) { //url获取token var content = actionContext.Request.Properties["MS_HttpContext"] as HttpContextBase; var token = content.Request.Headers["Token"]; if (!string.IsNullOrEmpty(token)) { //解密用户ticket,并校验用户名密码是否匹配 if (ValidateTicket(token)) { base.IsAuthorized(actionContext); } else { HandleUnauthorizedRequest(actionContext); } } //如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401 else { var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>(); bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute); if (isAnonymous) base.OnAuthorization(actionContext); else HandleUnauthorizedRequest(actionContext); } } //校验票据(数据库数据匹配) private bool ValidateTicket(string encryptToken) { bool flag = false; try { //获取数据库Token Dec.Models.TicketAuth model = Dec.BLL.TicketAuth.GetTicketAuthByToken(encryptToken); if (model.Token == encryptToken) //存在 { //未超时 flag = (DateTime.Now <= model.ExpireDate) ? true : false; } } catch (Exception ex) { } return flag; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
using System; using System.Web; using System.Web.Http; using System.Web.Security; using System.Net.Http; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Text; using OtherApi.Auth; //引用验证 namespace SpiderApi.Controllers { /// <summary> /// 用户授权接口 /// </summary> public class AccountController : ApiController { #region 用户登录授权 /// <summary> /// 用户登录授权 /// </summary> /// <param name="username">用户名</param> /// <param name="password">密码</param> /// <returns></returns> [Route("api/account/login")] [HttpGet] public HttpResponseMessage Login(string username, string password) { //定义 ResponseResult obj = new ResponseResult(); var model = GetLoginModel(username, password); if (model != null) { int userId = model.UserId; string Token = UntilHelper.Md5Encode(UntilHelper.GetExtGuidID(), 32); var dtNow = DateTime.Now; #region 将身份信息保存票据表中,验证当前请求是否是有效请求 //判断此用户是否存在票据信息 if (Dec.BLL.TicketAuth.GetTicketAuthByUserId(userId) != null) { //清空重置 Dec.BLL.TicketAuth.DeleteByUserId(userId); } Dec.Models.TicketAuth ticket = new Dec.Models.TicketAuth(); ticket.UserID = userId; ticket.Token = Token; ticket.CreateDate = dtNow; ticket.ExpireDate = dtNow.AddMinutes(30); //30分钟过期 Dec.BLL.TicketAuth.Add(ticket); #endregion //返回信息 obj.status = true; obj.message = "用户登录成功"; JObject jo = new JObject(); jo.Add("userid", userId); jo.Add("loginname", model.LoginName); jo.Add("nickname", model.NickName); jo.Add("usertype", model.UserType); //(int)UserTypeEnum.Seller jo.Add("token", Token); obj.info = jo; } else { obj.status = false; obj.message = "用户登录失败"; } var resultObj = JsonConvert.SerializeObject(obj, Formatting.Indented); HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(resultObj, Encoding.GetEncoding("UTF-8"), "application/json") }; return result; } #endregion #region 用户退出登录,清空Token /// <summary> /// 用户退出登录,清空Token /// </summary> /// <param name="userId">用户ID</param> /// <returns></returns> [Route("api/account/loginout")] [HttpGet] public HttpResponseMessage LoginOut(int userId) { //定义 ResponseResult obj = new ResponseResult(); try { //清空数据库该用户票据数据 Dec.BLL.TicketAuth.DeleteByUserId(userId); } catch (Exception ex) { } //返回信息 obj.status = true; obj.message = "成功退出"; var resultObj = JsonConvert.SerializeObject(obj); HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(resultObj, Encoding.GetEncoding("UTF-8"), "application/json") }; return result; } #endregion #region 查询Token是否有效 /// <summary> /// 查询Token是否有效 /// </summary> /// <param name="token">token</param> /// <returns></returns> [Route("api/account/validatetoken")] [HttpGet] public HttpResponseMessage ValidateToken(string token) { //定义 ResponseResult obj = new ResponseResult(); bool flag = ValidateTicket(token); if (flag) { //返回信息 obj.status = true; obj.message = "token有效"; } else { obj.status = false; obj.message = "token无效"; } var resultObj = JsonConvert.SerializeObject(obj); HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(resultObj, Encoding.GetEncoding("UTF-8"), "application/json") }; return result; } #endregion #region 获取用户账户余额 /// <summary> /// 获取用户账户余额 /// </summary> /// <param name="userId">用户ID</param> /// <returns></returns> [Route("api/account/amount")] [HttpGet] [AuthFilterOutside] //添加验证 public HttpResponseMessage GetAmount(int userId) { //定义 ResponseResult obj = new ResponseResult(); //获取数据库数据 Dec.Models.UserInfo model = Dec.BLL.UserInfo.GetUserInfoByUserId(userId); if (model != null) { //返回信息 obj.status = true; obj.message = "获取用户账户余额成功"; JObject jo = new JObject(); jo.Add("userid", model.UserId); jo.Add("amount", model.Amount); obj.info = jo; } else { obj.status = false; obj.message = "获取用户账户余额失败"; } var resultObj = JsonConvert.SerializeObject(obj); HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(resultObj, Encoding.GetEncoding("UTF-8"), "application/json") }; return result; } #endregion /// <summary> /// 用户充值接口 /// </summary> /// <param name="userid">用户ID</param> /// <param name="amount">充值金额</param> /// <returns></returns> [Route("api/account/recharge")] [HttpGet] [AuthFilterInside] public HttpResponseMessage Recharge(string userid, double amount) { //定义 ResponseResult obj = new ResponseResult(); //获取数据库数据 //返回信息 obj.status = true; obj.message = "操作成功,请等待第三方支付平台返回通知核实是否到账"; JObject jo = new JObject(); jo.Add("userid", "123456789"); jo.Add("amount", 125.80); obj.info = jo; var resultObj = JsonConvert.SerializeObject(obj); HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(resultObj, Encoding.GetEncoding("UTF-8"), "application/json") }; return result; } #region 验证票据是否有效 /// <summary> /// 验证票据是否有效 /// </summary> /// <param name="encryptToken">token</param> /// <returns></returns> private bool ValidateTicket(string encryptToken) { bool flag = false; try { //获取数据库Token Dec.Models.TicketAuth model = Dec.BLL.TicketAuth.GetTicketAuthByToken(encryptToken); if (model.Token == encryptToken) //存在 { //未超时 flag = (DateTime.Now <= model.ExpireDate) ? true : false; } } catch (Exception ex) { } return flag; } #endregion #region 用户登录 /// <summary> /// 用户登录 /// </summary> /// <param name="userName">用户名</param> /// <param name="userPwd">密码</param> /// <returns></returns> private Dec.Models.UserInfo GetLoginModel(string userName, string userPwd) { Dec.Models.UserInfo model = new Dec.Models.UserInfo(); try { if (!string.IsNullOrWhiteSpace(userName) && !string.IsNullOrWhiteSpace(userPwd)) { //数据库比对 model = Dec.BLL.UserInfo.GetUserInfoByUserNamePwd(userName, UntilHelper.Md5Encode(userPwd, 32)); } } catch (Exception ex) { } return model; } #endregion } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
////////////////////////////////////////////////////////////////// using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; namespace SpiderApi { public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { //WebApi文档 AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); } protected void Application_PostAuthorizeRequest() { //Enable Session HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
// Uncomment the following to provide samples for PageResult<T>. Must also add the Microsoft.AspNet.WebApi.OData // package to your project. 先安装Help Page包 HelpPage=>App_start=>HelpPageConfig.cs ////#define Handle_PageResultOfT using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http.Headers; using System.Reflection; using System.Web; using System.Web.Http; using SpiderApi.Models; #if Handle_PageResultOfT using System.Web.Http.OData; #endif namespace SpiderApi.Areas.HelpPage { /// <summary> /// Use this class to customize the Help Page. /// For example you can set a custom <see cref="System.Web.Http.Description.IDocumentationProvider"/> to supply the documentation /// or you can provide the samples for the requests/responses. /// </summary> public static class HelpPageConfig { [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "SpiderApi.Areas.HelpPage.TextSample.#ctor(System.String)", Justification = "End users may choose to merge this string with existing localized resources.")] [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "bsonspec", Justification = "Part of a URI.")] public static void Register(HttpConfiguration config) { //// Uncomment the following to use the documentation from XML documentation file. //开启解析 config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/Bin/SpiderApi.XML"))); //// Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type. //// Also, the string arrays will be used for IEnumerable<string>. The sample objects will be serialized into different media type //// formats by the available formatters. //config.SetSampleObjects(new Dictionary<Type, object> //{ // {typeof(string), "sample string"}, // {typeof(IEnumerable<string>), new string[]{"sample 1", "sample 2"}} //}); //添加映射 config.SetSampleResponse(Sample.BatchSendMessageResponse(), new MediaTypeHeaderValue("text/json"), "MessageQueue", "BatchSendMessage"); config.SetSampleResponse(Sample.BatchReceiveMessageResponse(), new MediaTypeHeaderValue("text/json"), "MessageQueue", "BatchReceiveMessage"); config.SetSampleResponse(Sample.DeleteMessageResponse(), new MediaTypeHeaderValue("text/json"), "MessageQueue", "DeleteMessage"); config.SetSampleResponse(Sample.BatchDeleteMessageResponse(), new MediaTypeHeaderValue("text/json"), "MessageQueue", "BatchDeleteMessage"); config.SetSampleResponse(Sample.ChangeMessageVisibilityResponse(), new MediaTypeHeaderValue("text/json"), "MessageQueue", "ChangeMessageVisibility"); // Extend the following to provide factories for types not handled automatically (those lacking parameterless // constructors) or for which you prefer to use non-default property values. Line below provides a fallback // since automatic handling will fail and GeneratePageResult handles only a single type. #if Handle_PageResultOfT config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(GeneratePageResult); #endif // Extend the following to use a preset object directly as the sample for all actions that support a media // type, regardless of the body parameter or return type. The lines below avoid display of binary content. // The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object. config.SetSampleForMediaType( new TextSample("Binary JSON content. See http://bsonspec.org for details."), new MediaTypeHeaderValue("application/bson")); //// Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format //// and have IEnumerable<string> as the body parameter or return type. //config.SetSampleForType("[0]=foo&[1]=bar", new MediaTypeHeaderValue("application/x-www-form-urlencoded"), typeof(IEnumerable<string>)); //// Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on the controller named "Values" //// and action named "Put". //config.SetSampleRequest("1234", new MediaTypeHeaderValue("text/plain"), "Values", "Put"); //// Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png" //// on the controller named "Values" and action named "Get" with parameter "id". //config.SetSampleResponse(new ImageSample("../images/aspNetHome.png"), new MediaTypeHeaderValue("image/png"), "Values", "Get", "id"); //// Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent<string>. //// The sample will be generated as if the controller named "Values" and action named "Get" were having string as the body parameter. //config.SetActualRequestType(typeof(string), "Values", "Get"); //// Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent<string>. //// The sample will be generated as if the controller named "Values" and action named "Post" were returning a string. //config.SetActualResponseType(typeof(string), "Values", "Post"); } #if Handle_PageResultOfT private static object GeneratePageResult(HelpPageSampleGenerator sampleGenerator, Type type) { if (type.IsGenericType) { Type openGenericType = type.GetGenericTypeDefinition(); if (openGenericType == typeof(PageResult<>)) { // Get the T in PageResult<T> Type[] typeParameters = type.GetGenericArguments(); Debug.Assert(typeParameters.Length == 1); // Create an enumeration to pass as the first parameter to the PageResult<T> constuctor Type itemsType = typeof(List<>).MakeGenericType(typeParameters); object items = sampleGenerator.GetSampleObject(itemsType); // Fill in the other information needed to invoke the PageResult<T> constuctor Type[] parameterTypes = new Type[] { itemsType, typeof(Uri), typeof(long?), }; object[] parameters = new object[] { items, null, (long)ObjectGenerator.DefaultCollectionSize, }; // Call PageResult(IEnumerable<T> items, Uri nextPageLink, long? count) constructor ConstructorInfo constructor = type.GetConstructor(parameterTypes); return constructor.Invoke(parameters); } } return null; } #endif } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* API接口测试工具 - WebApiTestClient使用--Nuget引入组件 --A Simple Test Client for ASP.NET Web API */ /* 1、修改Api.cshtml文件 通过上述步骤,就能将组件WebAPITestClient引入进来。下面我们只需要做一件事:打开文件 (根据 Areas\HelpPage\Views\Help) Api.cshtml 并添加以下内容: @Html.DisplayForModel("TestClientDialogs") @Html.DisplayForModel("TestClientReferences") 添加后Api.cshtml文件的代码如下 */ @using System.Web.Http @using WebApiTestClient.Areas.HelpPage.Models @model HelpPageApiModel @{ var description = Model.ApiDescription; ViewBag.Title = description.HttpMethod.Method + " " + description.RelativePath; } <link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" /> <div id="body" class="help-page"> <section class="featured"> <div class="content-wrapper"> <p> @Html.ActionLink("Help Page Home", "Index") </p> </div> </section> <section class="content-wrapper main-content clear-fix"> @Html.DisplayForModel() </section> </div> @Html.DisplayForModel("TestClientDialogs") @section Scripts{ <link href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" /> @Html.DisplayForModel("TestClientReferences") } |
from:http://blog.csdn.net/smartsmile2012/article/details/52936011
View Details一,简介 Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架。它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息。 可访问其官方网站:https://github.com/SignalR/ 获取更多资讯。 二,实现机制 SignalR 的实现机制与 .NET WCF 或 Remoting 是相似的,都是使用远程代理来实现。在具体使用上,有两种不同目的的接口:PersistentConnection 和 Hubs,其中 PersistentConnection 是实现了长时间的 Javascript 轮询(类似于 Comet),Hub 是用来解决实时信息交换问题,它是利用 Javascript 动态载入执行方法实现的。SignalR 将整个连接,信息交换过程封装得非常漂亮,客户端与服务器端全部使用 JSON 来交换数据。 下面就 Hubs 接口的使用来讲讲整个流程: 1,在服务器端定义对应的 hub class; 2,在客户端定义 hub class 所对应的 proxy 类; 3,在客户端与服务器端建立连接(connection); 4,然后客户端就可以调用 proxy 对象的方法来调用服务器端的方法,也就是发送 request 给服务器端; 5,服务器端接收到 request 之后,可以针对某个/组客户端或所有客户端(广播)发送消息。 三,Hub 示例教程 1,工具准备 SignalR 运行在 .NET 4.5 平台上,所以需要安装 .NET 4.5。为了方便演示,本示例使用 ASP.NET MVC 在 Win 7 系统来实现。这需要安装 ASP.NET MVC 3 或 ASP.NET MVC 4。 2,建立工程 打开 VS2010/VS2012 新建名为 SignalRTutorial 的 ASP.NET MVC 3 Web Application 工程,选择 Internet Application 模板, Razor […]
View Details