首先在windows上安装好Redis,RabbitMQ Redis-cli使用示例 ModelContext.cs代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class ModelContext : DbContext { //您的上下文已配置为从您的应用程序的配置文件(App.config 或 Web.config) //连接字符串。 public ModelContext() : base("name=default") { } public virtual DbSet<Person> Person { get; set; } } public class Person { public int Id { get; set; } public string Id2 { get; set; } public string Name { get; set; } } |
在 Package Manager Console 下运行命令 Enable-Migrations 这个命令将在项目下创建文件夹 Migrations The Configuration class 这个类允许你去配置如何迁移,对于本文将使用默认的配置(在本文中因为只有一个 Context, Enable-Migrations 将自动对 context type 作出适配); An InitialCreate migration (本文为201702220232375_20170222.cs)这个迁移之所以存在是因为我们之前用 Code First 创建了数据库, 在启用迁移前,scaffolded migration 里的代码表示在数据库中已经创建的对象,本文中即为表 Person(列 Id 和 Name). 文件名包含一个 timestamp 以便排序(如果之前数据库没有被创建,那么 InitialCreate migration 将不会被创建,相反,当我们第一次调用 Add-Migration 的时候所有表都将归集到一个新的 migration 中) 多个实体锁定同一数据库 当使用 EF6 之前的版本时,只会有一个 Code First Model 被用来生成/管理数据库的 Schema, 这将导致每个数据库只会有一张 __MigrationsHistory 表,从而无法辨别实体与模型的对应关系。 从 EF6 开始,Configuration 类将会包含一个 ContextKey 属性,它将作为每一个 Code First Model 的唯一标识符, __MigrationsHistory 表中一个相应地的列允许来自多个模型(multiple models)的实体共享表(entries),默认情况下这个属性被设置成 context 的完全限定名。 定制化迁移 在 Package Manager Console 中运行命令 Add-Migration XXXXXXXXX 生成的迁移如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class _20170222 : DbMigration { public override void Up() { CreateTable( "dbo.People", c => new { Id = c.Int(nullable: false, identity: true), Id2 = c.String(), Name = c.String(), }) .PrimaryKey(t => t.Id); } public override void Down() { DropTable("dbo.People"); } } |
Configuration.cs代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
internal sealed class Configuration : DbMigrationsConfiguration<EF.ModelContext> { public Configuration() { AutomaticMigrationsEnabled = false; } protected override void Seed(EF.ModelContext context) { } } |
我们对迁移做些更改: […]
View Details下载地址 https://www.microsoft.com/zh-CN/download/details.aspx?id=18970 快速描述 Microsoft Visual Studio International Feature Pack 2.0 Visual Studio International Feature Pack 2.0 包含一组控件和类库,设计用来帮助.NET开发人员创建国际化程序。 概述 Visual Studio International Feature Pack 2.0 是对 1.0 版本( 1.0 版的产品名是 Microsoft Visual Studio International Pack 1.0 SR1) 的扩展,包含一组控件和类库,设计用来帮助.NET开发人员创建国际化程序。 1, Yomigana Framework 包含了类库和控件。 a, 类库:Yomigana 类库容许对串(string)类型加注 Yomigana,同时也支持对一般类型的注解功能,任何实现了IEnumerable接口的对象都可以被串类型和泛型的实例注解。为了简化复杂的注解字符串比较特设计了支持各种日文比较选项的比较类型。 1) 通用的一些类,用泛型实现对一个可枚举的类型注音。 2) 特殊目的的一些类,用以上泛型实现对一个字符串用某种类型中注音。 3) 特殊目的的一些StringAnnotation 类,用以上泛型实现对一个字符串用字符串注音,包括解析和格式化功能。 4) 一个比较器类,使用以上类实现比较字符串。 5) 一个实现了 IEnumerable 的数据结构,把一个字符串分成枚举的字符串段,并用 IEnumerator 输出。 b, 控件: 1) 增强的Ajax/WPF/WinForm 文本框(TextBox)控件 用来根据用户的输入捕获读音。 2) 一个增强的使用Ruby标签的ASP.NET Label控件。 2, Chinese Text Alignment Class Library and TextBox Controls 包含支持简体中文文本对齐的WinForm 和 WPF 的TextBox控件, 以及供帮助开发人员很容易地按中文文本对齐显示字符串的一个类库。 3, Chinese Auto Complete Class Library and […]
View Details调试的时候报这样的错误 解决办法: 工具--选项--调试--常规--启用asp.net的JavaScript调试(chrome和ie)去掉勾选 from:http://www.mamicode.com/info-detail-2349622.html
View Details解决问题前,首先确定[FormBodyAttribute]的定义以及功能范围,相关资料: https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api 其实文中已经讲得足够详细,一般来讲FormUri获取参数不会存在什么疑惑,但在不了解规则的情况下如何设置和获取FormBody标识的值却有些迷惑:我到底该怎么传递参数api才能够获取到参数?很多文章给出的解决方案是利用="json string"这样的方式进行提交,但实在太别扭了。这样的代码写出去会被打吧…所以,到底该怎么请求呢? 如果你仔细阅读过文章,相信你应该注意到了这一段: When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. 意思是对于被标记为FromBody的parameter,WebApi默认会根据Content-Type中选择格式化方法。由于Web程序中常常使用JSON方式传递数据,所以这里只针对Content-Type="application/json"的请求进行分析。接着看下一句: In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object). 其实到这里已经给出解决方案了,即Content-Type="application/json"的请求都需要将参数转换为JSON string,而非JSON Object. 接下来代码说话的时间到了: 1)创建一个复杂对象的实体类DataParameter: 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 [Serializable] public class DataParameter { public DataParameter() […]
View Details继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理。 这里我使用Jquery 来发起异步请求实现数据调用。 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用。 一、无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetUser() : 也可以用$.ajax({type:"get"}) 方式,正确的获得了返回数据: 二、传递一个参数的Get请求 通常我们需要传递参数只需要指定ajax方法的data属性即可: data:{"name":"赵大宝"} 后台正确的返回数据: 三、传递两个或多个参数的Get请求 按照上面的方法,对于多个参数我们可以很容易就写出来: data:{"name":"赵大宝","age":12} 后台正确的返回数据: 四、无参数的Post请求 我们可以使用$.post() 或$.ajax({type:"post"}) 来发起post请求: 后台正确的返回了数据: 五、传递一个参数的Post请求: 首先这里需要提醒大家一下,我们在修改完后台代码后,如果没有重新生成项目,那么在请求时就会报错:“未找到与请求***匹配的HTTP资源” : 所以,我们只要我们修改了后台代码,就一定要重新生成一下: 不过,当我们重新生成项目,再次发送请求,看到的仍然是404错误,再次检查一番代码,也没有发现是哪里的问题。 事实上,ASP.NET Web API能够正确的识别我们的UserController控制器处理Post /api/user ,但却不能找到一个可以接受的方法来处理请求。 也就是说,Web API接收到的请求能够找到User控制器,但在该控制器中找不到名称为Def 的这个Action。 那我们要怎么来解决呢? 通过搜索MSDN上Web API官网中的说明,我们可以找到下面的一段介绍: 即在Action 方法中我们需要使用 [FromBody] 属性标签来标明属性。 修改后,再次发送请求,我们可以看到,Status Code 为200,请求发送成功。 可以看到,在post请求中,方法的参数必须要用 [FromBody] 属性来修饰才可以, [FromBody] 就告诉Web API 要从post请求体重去获取参数的值。 但让我们诧异的却是,后台返回的数据中name的值为空。 通过调试,我们可以看到,后台Action 中接收到的name值为null。 通过上面的测试我就也能够猜测到,Web API 要求请求传递的 [FromBody] 参数,肯定是有一个特定的格式,才能被正确的获取到。而这种特定的格式并不是我们常见的 key=value 的键值对形式。Web API 的模型绑定器希望找到 [FromBody] 里没有键名的值,也就是说, 不是 key=value ,而是 =value 。 现在,咱们把data中的key设置为空,然后再次发送请求: 测试可见,后台正确的接收到了数据: 六、传递两个参数的Post请求 按理说,一个参数的请求实现了,那么传递两个或者多个参数也就很顺利了,对于两个参数的后台接收方法,我们可能会这样来写: 但事实证明,这样是错误的。 那到底两个或者多个参数我们要怎样来定义呢? […]
View Details今天在来一发 webapi的一个知识点 相信用过webapi的对这个错误 已经看在眼里 痛在心里了把 我百度也搜了一下 看了一下 然后发现他们的解决办法 并没有什么软用。 然后想起来当时上学的时候 老师讲过这个知识点 然后又找到了 老师 0.0 当时老师写的一个笔记。我直接上截图了。 在webapiConfig里面加一行代码 就好。 然后 又是我们熟悉而可爱的json了。 代码是 GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); from:https://www.cnblogs.com/uglyman/p/6890706.html?utm_source=itdadao&utm_medium=referral
View Details最近在工作中遇到一个需求,需要使用 nginx 反向代理websocket,经过查找一番资料,目前已经测试通过,所以这篇文章主要给大家介绍了Nginx反向代理WebSocket配置的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。 实现方案 采用目前比较成熟的WebSocket技术,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择。其为HTML5的一部分,WebSocket相较于原来开发这类app的方法来说,其能使开发更加地简单。大部分现在的浏览器都支持WebSocket,比如Firefox,IE,Chrome,Safari,Opera,并且越来越多的服务器框架现在也同样支持WebSocket。 WebSocket集群 在实际的生产环境中,要求多个WebSocket服务器必须具有高性能和高可用,那么WebSocket协议就需要一个负载均衡层,NGINX从1.3开始支持WebSocket,其可以作为一个反向代理和为WebSocket程序做负载均衡。 Nginx配置 注:看官方文档说 Nginx 在 1.3 以后的版本才支持 websocket 反向代理,所以要想使用支持 websocket 的功能,必须升级到 1.3 以后的版本 NGINX通过允许一个在客户端和后端服务器之间建立的隧道来支持WebSocket。为了NGINX发送来至于客户端Upgrade请求到后端服务器,Upgrade和Connection头部必须被设置明确。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
upstream wsbackend { server 127.0.0.1:8080; server 127.0.0.1:8081; } server { listen 80; server_name ws.52itstyle.com; location / { proxy_pass http://wsbackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } |
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 |
<strong>前端配置:</strong> $(function(){ socket.init(); }); //Nginx反向代理实现websocket var basePath = "ws://ws.52itstyle.com//acts_competition/"; socket = { webSocket : "", init : function() { if ('WebSocket' in window) { webSocket = new WebSocket(basePath+'webSocketServer'); } else if ('MozWebSocket' in window) { webSocket = new MozWebSocket(basePath+"webSocketServer"); } else { webSocket = new SockJS(basePath+"sockjs/webSocketServer"); } webSocket.onerror = function(event) { //alert("websockt连接发生错误,请刷新页面重试!") }; webSocket.onopen = function(event) { }; webSocket.onmessage = function(event) { }; }, sendData : function(data) { webSocket.send(data); }, } |
最后,重启下Nginx即可。 反向代理服务器在支持WebSocket时面临的挑战 WebSocket是端对端的,所以当一个代理服务器从客户端拦截一个Upgrade请求,它需要去发送它自己的Upgrade请求到后端服务器,也包括合适的头。 因为WebSocket是一个长连接,不像HTTP那样是典型的短连接,所以反向代理服务器需要允许连接保持着打开,而不是在它们看起来空闲时就将它们关闭。 总结 以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。 原文链接:http://blog.52itstyle.com/archives/736/
View DetailsWEBAPI中的Request是HttpRequestMessage类型,不能像Web传统那样有querystring和from 方法接收参数,而传统的HttpReqest的基类是HttpReqestBase 所以这里我们就直接使用(HttpContextBase)Request.Properties["MS_HttpContext"]
1 2 3 4 5 6 |
public void Post([FromBody]string value) { HttpContextBase context = (HttpContextBase)Request.Properties["MS_HttpContext"];//获取传统context HttpRequestBase request = context.Request;//定义传统request对象 string name = request.Form["name"]; } |
1.获取遍历路由参数
1 2 3 4 5 6 7 8 9 |
//获取路由参数 IDictionary<string, object> dic = this.RequestContext.RouteData.Values; StringBuilder builder = new StringBuilder(); foreach (var item in dic) { builder.AppendFormat("key:{0},value:{1}", item.Key, item.Value); builder.AppendLine(); } return builder.ToString(); |
2.遍历表单参数
1 2 3 4 5 6 7 8 9 10 |
////获取表单参数 HttpContextBase context = (HttpContextBase)Request.Properties["MS_HttpContext"];//获取传统context HttpRequestBase request = context.Request;//定义传统request对象 StringBuilder builder = new StringBuilder(); foreach (string item in request.Form.Keys) { builder.AppendFormat("key:{0},value:{1}", item, request.Form[item]); builder.AppendLine(); } return builder.ToString(); |
from:http://www.cnblogs.com/tianma3798/p/5089890.html
View Details由于 web api 项目通常是被做成了一个独立站点,来提供数据,在做web api 项目的时候,不免前端会遇到跨域访问接口的问题。 刚开始没做任何处理,用jsonp的方式调用 web api 接口,总是报一个错误,如下: 如果你想用JSONP来获得跨域的数据,WebAPI本身是不支持javascript的callback的,它返回的JSON是这样的:
1 |
{"YourSignature":"嫁人要嫁程序员,钱多话少死得早"} |
然而,JSONP请求期望得到这样的JSON:
1 |
jQuery123456([{"YourSignature":"嫁人要嫁程序员,钱多话少死得早"}]) |
所以我们需要对WebAPI做拓展,让它支持这样的callback 解决方案如下: 只需要给全局注册一个JsonCallbackAttribute,就可以判断接口的访问是属于跨域,还是非跨域,正常的返回。 因为我们的接口,可能是用来给 移动端(Android 、IOS)做数据接口,也有可能是给网站用,所以,考虑到可能存在跨域的问题。
1 |
GlobalConfiguration.Configuration.Filters.Add(new JsonCallbackAttribute()); |
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 |
public class JsonCallbackAttribute : ActionFilterAttribute { private const string CallbackQueryParameter = "callback"; public override void OnActionExecuted(HttpActionExecutedContext context) { var callback = string.Empty; if (IsJsonp(out callback)) { var jsonBuilder = new StringBuilder(callback); jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result); context.Response.Content = new StringContent(jsonBuilder.ToString()); //context.Response.Content = new StringContent("C(\"a\")"); } base.OnActionExecuted(context); } private bool IsJsonp(out string callback) { callback = System.Web.HttpContext.Current.Request.QueryString[CallbackQueryParameter]; return !string.IsNullOrEmpty(callback); } |
结合下面图片不难开出,请求的地址带回了,callback的参数标识。 测试代码如下:
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 |
<html> <head> <title>团队信息列表</title> <script type="text/javascript" src="@Url.Content("~/scripts/jquery-1.7.1.js")"></script> </head> <body> <ul id="contacts"></ul> <script type="text/javascript"> $(function () { $.ajax({ Type: "GET", url: "http://app.uni2uni.com/api/CloudService/GetAllGroup", dataType: "jsonp", success: listContacts }); }); function listContacts(contacts) { alert(contacts); $.each(contacts.data, function (index, contact) { var html = "<li><ul>"; html += "<li>GroupName: " + contact.GroupName + "</li>"; html += "<li>GroupPicture:" + contact.GroupPicture + "</li>"; html += "</ul>"; $("#contacts").append($(html)); }); } </script> </body> </html> |
返回接口如下: 相关文章推荐:http://diaosbook.com/Post/2013/12/27/tips-for-aspnet-webapi-cors from:https://www.cnblogs.com/Kummy/p/3767269.html
View Details原文地址:C#中HttpClient使用注意:预热与长连接 最近在测试一个第三方API,准备集成在我们的网站应用中。API的调用使用的是.NET中的HttpClient,由于这个API会在关键业务中用到,对调用API的整体响应速度有严格要求,所以对HttpClient有了格外的关注。 开始测试的时候,只在客户端通过HttpClient用PostAsync发了一个http post请求。测试时发现,从创建HttpClient实例,到发出请求,到读取到服务器的响应数据总耗时在2s左右,而且多次测试都是这样。2s的响应速度当然是无法让人接受的,我们希望至少控制在100ms以内。于是开始追查这个问题的原因。 在API的返回数据中包含了该请求在服务端执行的耗时,这个耗时都在20ms以内,问题与服务端API无关。于是把怀疑点放到了网络延迟上,但ping服务器的响应时间都在10ms左右,网络延迟的可能性也不大。 当我们正准备换一个网络环境进行测试时,突然想到,我们的测试方式有些问题。我们只通过HttpClient发了一个PostAsync请求,假如HttpClient在第一次调用时存在某种预热机制(比如在EF中就有这样的机制),现在2s的总耗时可能大多消耗在HttpClient的预热上。 于是修改测试代码,将调用由1次改为100次,然后恍然大悟地发现——只有第1次是2s,接下来的99次都在100ms以内。果然是HttpClient的某种预热机制在搞鬼! 既然知道了是HttpClient预热机制的原因,那我们可以帮HttpClient进行热身,减少第一次请求的耗时。我们尝试了一种预热方式,在正式发http post请求之前,先发一个http head请求,代码如下:
1 2 3 4 |
_httpClient.SendAsync(new HttpRequestMessage { Method = new HttpMethod("HEAD"), RequestUri = new Uri(BASE_ADDRESS + "/") }) .Result.EnsureSuccessStatusCode(); |
经测试,通过这种热身方法,可以将第一次请求的耗时由2s左右降到1s以内(测试结果是700多ms)。 在知道第1次HttpClient请求耗时2s的真相之后,我们将目光转向了剩下的99次耗时100ms以内的请求,发现绝大部分请求都在50ms以上。有没有可能将之降至50ms以下?而且,之前一直有这样的纠结:每次调用是不是一定要对HttpClient进行Dispose()?是不是要将HttpClient单例或者静态化(声明为静态变量)?借此机会一起研究一下。 在HttpClient的背后,有一个对请求响应速度有着不容忽视影响的东东——TCP连接。一个HttpClient实例会关联一个TCP连接,在对HttpClient进行Dispose时,会关闭TCP连接(我们用Wireshark进行网络抓包也验证了这一点)。 在之前的测试中,我们每次用HttpClient发请求时,都是新建一个HttpClient实例,用完就对它进行Dispose,代码如下:
1 2 3 4 |
using (var httpClient = new HttpClient() { BaseAddress = new Uri(BASE_ADDRESS) }) { httpClient.PostAsync("/", new FormUrlEncodedContent(parameters)); } |
所以每次请求时都要经历新建TCP连接->传数据->关闭连接(也就是通常所说的短连接),而且雪上加霜的是请求用的是https,建立TCP连接时还需要一个基于公私钥加解密的key exchange过程:Client Hello -> Server Hello -> Certificate -> Client Key Exchange -> New Session Ticket。 如果我们想将请求响应时间降至50ms以下,就必须从这个地方下手——重用TCP连接(也就是通常所说的长连接)。要实现长连接,首先需要的就是在HttpClient第1次请求后不关闭TCP连接(不调用Dispose方法);而要让后续的请求继续使用这个未关闭的TCP连接,我们必须要使用同一个HttpClient实例;而要使用同一个HttpClient实例,就得实现HttpClient的单例或者静态化。之前的3 个问题,由于要解决第1个问题,后2个问题变成了别无选择。 为了实现长连接,我们将HttpClient的调用代码改为如下的样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class HttpClientTest { private static readonly HttpClient _httpClient; static HttpClientTest() { _httpClient = new HttpClient() { BaseAddress = new Uri(BASE_ADDRESS) }; //帮HttpClient热身 _httpClient.SendAsync(new HttpRequestMessage { Method = new HttpMethod("HEAD"), RequestUri = new Uri(BASE_ADDRESS + "/") }) .Result.EnsureSuccessStatusCode(); } public async Task<string> PostAsync() { var response = await _httpClient.PostAsync("/", new FormUrlEncodedContent(parameters)); return await response.Content.ReadAsStringAsync(); } } |
然后测试一下请求响应时间:
1 2 3 4 5 6 7 8 9 10 11 |
Elapsed:750ms Elapsed:31ms Elapsed:30ms Elapsed:43ms Elapsed:27ms Elapsed:29ms Elapsed:28ms Elapsed:35ms Elapsed:36ms Elapsed:31ms .... |
除了第1次请求,接下来的99次请求绝大多数都在50ms以内。TCP长连接的效果必须的! 通过Wireshak抓包也验证了长连接的效果: 这时,你也许会产生这样的疑问:将HttpClient声明为静态变量,会不会存在线程安全问题?我们当时也有这样的疑问,后来在stackoverflow上找到了答案:
1 2 3 4 5 6 7 8 9 10 |
As per the comments below (thanks @ischell), the following instance methods are thread safe (all async): CancelPendingRequests DeleteAsync GetAsync GetByteArrayAsync GetStreamAsync GetStringAsync PostAsync PutAsync SendAsync |
HttpClient的所有异步方法都是线程安全的,放心使用。 到这里,HttpClient的问题是不是可以完美收官了?。。。稍等,还有一个问题。 客户端虽然保持着TCP连接,但TCP连接是两口子的事,服务器端呢?你不告诉服务器,服务器怎么知道你要一直保持TCP连接呢?对于客户端,保持TCP连接的开销不大;但是对于服务器,则完全不一样的,如果默认都保持TCP连接,那可是要保持成千上万客户端的连接啊。所以,一般的Web服务器都会根据客户端的诉求来决定是否保持TCP连接,这就是keep-alive存在的理由。 所以,我们还要给HttpClient增加一个Connection:keep-alive的请求头,代码如下:
1 |
_httpClient.DefaultRequestHeaders.Connection.Add("keep-alive"); |
现在终于可以收官了。但是肯定不完美,分享的只是解决问题的过程。 from:https://www.cnblogs.com/JustYong/p/5872296.html
View Details