Charles 手机抓包连接教程,亲身试过

最近使用Charles抓包,在网上搜教程,很多教程都不完整,弄了好久才弄好连接手机抓包功能,这次自己整理一下,分享出来,也便于以后自己使用,下面开始吧。

1、     安装Charles

破解安装包地址:http://pan.baidu.com/s/1kUUj2gn

包含证书和破解jar包

2、安装好,Charles之后,进行配置,要确保在一个wifi

环境中,使用ifconfig en0查看电脑连接wifi所用的ip:

或者在打开网络偏好设置中,查看电脑的ip地址:

3、打开CharlesProxy->Proxy Settings,选中Enabel transparent HTTPproxying。点击ok。Port一般都是8888,这个要和下一步手机中的端口相同。

4、打开手机,设置->无线局域网下的HTTP代理,选择手动:

5、点击返回,电脑中Charles会出现一个提示框,点击allow。

如果没有出现点击Proxy->Access control settings,添加你的手机ip。

6、现在我们用我们的iPhone打开 safari中输入这个网址,安装描述文件。

IOS9输入:

https://www.charlesproxy.com/getssl

其他:

http://www.charlesproxy.com/getssl

注:IOS9开始使用https

下载描述文件安装。

如果提示连接网络失败关闭电脑wifi重新打开一次,并重启Charles就可以了。

Announcing .NET Core 1.1

We are excited to announce the release of .NET Core 1.1 RTM, the first “Current” release. You can start creating .NET Core 1.1 apps, today, in Visual Studio 2015, Visual Studio 2017 RC, Visual Studio Code and Visual Studio for the Mac.

We used the 1.1 release to achieve the following improvements:

  • .NET Core: Add distros and improve performance.
  • ASP.NET Core: Improve Kestrel, Azure support and productivity.
  • EF Core: Azure and SQL 2016 support.

News flash: ASP.NET Core 1.1 with Kestrel was ranked as the fastest mainstream fullstack web framework in the TechEmpower plaintext benchmark.

News flash: Google Cloud is joining the .NET Foundation Technical Steering Group. Welcome, Google!

You can see all the .NET Core changes in detail in the .NET Core 1.1 release notes. It’s a small delta on the .NET Core 1.1 Preview 1 release that we shipped 3 weeks ago.

Installing

You can install the new release from the .NET Core downloads page. .NET Core is a Current release. Make sure to click the “Current” button to see the .NET Core 1.1 download links.

Distributions

Support for the following distributions was added:

  • Linux Mint 18
  • OpenSUSE 42.1
  • macOS 10.12 (also added to .NET Core 1.0)
  • Windows Server 2016 (also added to .NET Core 1.0)

You can see the full list of supported distributions in the .NET Core 1.1 release notes.

Documentation

.NET Core documentation has been updated for the release and will continue to be updated. We are also in the process of making visual and content updates to the .NET Core docs to make the docs easier and more compelling to use.

The ASP.NET Core and Entity Framework, C# and VB docs were moved to docs.microsoft.com as part of this release. F# documentation was added a few months ago.

Documentation on docs.microsoft.com open source. You can help us make it better by filing issues and making contributions on GitHub. Best places to start are dotnet/docs and aspnet/docs.

Performance

We were recently informed by the fine folks at TechEmpower that ASP.NET Core 1.1 with Kestrel was ranked as the fastest mainstream fullstack web framework in the TechEmpower plaintext benchmark. That’s a great result, and the result of significant engineering effort.

We adopted a performance optimization for the CoreCLR runtime called Profile-Guided Optimization (PGO), for the .NET Core 1.1 Windows version. We’ve use this technique for the .NET Framework for many years, but had not yet used it for .NET Core. This improvement was not included in the earlier .NET Core 1.1 Preview 1 release.

PGO optimizes C++ compiler-generated binaries with information it records from apps it observes in our lab. We call this process “training”. It’s about as exciting as 6AM runs in the dark during the Winter. PGO records info about which codepaths are used in a binary and in what order. For this release, we used a simple “Hello World” app for training.

We saw a 15% improvement with the ASP.NET MusicStore app running with a PGO-optized CoreCLR in our lab and believe that these improvements will be representative to other Web applications. We hope to see greater improvements in the future as we increase the pool of apps we train with.

For Linux and macOS, we compile CoreCLR with Clang/LLVM. We intend to use the Clang version of PGO in the next release. Very preliminary scouting of Clang PGO suggests that we will see similar benefits.

APIs

There are 1380 new APIs in .NET Core 1.1. Many of the new APIs were added to support the product itself, include reading portable PDBs. .NET Core 1.1 supports .NET Standard 1.6.

.NET Standard 2.0 support is coming in an upcoming release (in 2017). It is not part of .NET Core 1.1.

Using .NET Core 1.1

You can start by installing .NET Core 1.1. You can either install it globally using the .NET Core 1.1 installer or package manager for your operating system or try it an isolated (and easily removable) environment by downloading .NET Core as a zip.

Safe side-by-side install

You can safely globally install .NET Core 1.1 on a machine that already has .NET Core 1.0.

The dotnet new command creates new templates that reference the latest runtime on the machine. This may not be desired. If not, you can hand-edit the versions in the resulting project.json to earlier version numbers. Based on feedback, we will be changing this behavior in the new version of the tools, at the same time we release the final version of Visual Studio 2017. If you do not use dotnet new to create new projects, but rely on Visual Studio, then you are not affected.

Try it out

You can try .NET Core out with the command line tools, using these commands in your command prompt or terminal.

dotnet new
dotnet restore
dotnet run

You can also try out .NET Core 1.1 with a dotnet-bot sample we created for using .NET Core with Docker (although you don’t have to use Docker).

Upgrading Existing .NET Core 1.0 Projects

You can upgrade existing .NET Core 1.0 projects to .NET Core 1.1. I will show you the new project.json file that the updated dotnet new now produces. It’s the best way to see the new version values that you need to copy/paste into your existing project.json files. There are no automated tools to upgrade projects to later .NET Core versions.

The default .NET Core 1.1 project.json file follows:

{
version: 1.0.0-*,
buildOptions: {
debugType: portable,
emitEntryPoint: true
},
dependencies: {},
frameworks: {
netcoreapp1.1: {
dependencies: {
Microsoft.NETCore.App: {
type: platform,
version: 1.1.0
}
},
imports: dnxcore50
}
}
}
view rawproject.json hosted with ❤ by GitHub

This project.json file is very similar to what your .NET Core 1.0 project.json looks like, with the exception of the netcoreapp1.1 and 1.1.0target framework and meta-package version strings, respectively.

You can use the following substitutions to help you update project.json files that you want to move temporarily or permanently to .NET Core 1.1.

  • Update the netcoreapp1.0 target framework to netcoreapp1.1.
  • Update the Microsoft.NETCore.App package version from 1.0.x (for example, 1.0.0 or 1.0.1) to 1.1.0.

Upgrading .NET Standard Library Projects

There is no need to update .NET Standard Library projects.

We did publish a NETStandard.Library 1.6.1 meta package, however, there is no benefit in referencing it for producing libraries. The updated package has been provided as a dependency for the updated Microsoft.NETCore.App 1.1 metapackage.

Using .NET Core 1.1 Docker Images

You can use .NET Core 1.1 with Docker. You can find updated images at microsoft/dotnet.

The latest tag has been updated to point to the .NET Core 1.1 SDK. This is a departure from our earlier plan, as discussed in the 1.1 Preview 1 post. We looked at other platforms that have Current and LTS and saw that latest does indeed point to the latest version. Makes sense.

There are two new Runtime tags for .NET Core 1.1:

  • Linux: 1.1.0-runtime
  • Windows: 1.1.0-runtime-nanoserver

There are two new SDK tags for .NET Core 1.1:

  • Preview 2-based SDK, using project.json: 1.1.0-sdk-projectjson
  • Preview 3-based SDK, using CSProj: 1.1.0-sdk-msbuild, .

You can try .NET Core 1.1 with the [dotnetapp-current sample][dotnetapp-current] in the .NET Core Docker Samples repository. The other samples can be easily modified to also depend the .NET Core 1.1 images, by updating both the project.json and Dockerfile files with the appropriate version strings (all of which are provided above).

Current Release

In the earlier .NET Core 1.1 blog post, I described that we have adopted the industry practice of differentiated releases, which we’ve called “Long-term Support (LTS)” and “Current”. .NET Core 1.1 is a Current release and also the first one. Once a given Current release has shipped, we expect very few updates, hopefully only security updates.

We recommend that most developers adopt LTS releases. It’s also the default experience we’ll include in Visual Studio. We do hope that some of you adopt Current releases to give us feedback, as well. It’s hard to quantify it, but we thinking an 80/20 split between LTS and Current across the entire .NET Core developer base would be about right.

Closing

Please try the new .NET Core release and give us feedback. There are a lot of key improvements across .NET Core 1.1, ASP.NET Core and EF Core that will make your apps better and faster. It’s the first Current release, providing you with feature faster, provided you are happy with updating .NET Core more quickly than the LTS multi-year supported releases.

To recap, the biggest changes are:

  • Performance improvements, enough to make a very positive first entry on the TechEmpower benchmarks.
  • Addition of four OS distros.
  • 10s of new features and 100s of bug fixes.
  • Updated documentation.

Thanks to everyone who adopted .NET Core 1.0 and .NET Core 1.1 Preview 1 that gave us feedback. We appreciate all of the contribution and engagement! Please tell us what you think of the latest release.

You can start creating .NET Core 1.1 apps, today, in Visual Studio 2015, Visual Studio 2017 RC, Visual Studio Code and Visual Studio for the Mac.

.NET 应用迁移到 .NET Core:调查案例

上周已经发过三篇文章讲述做.NET 应用迁移到.NET Core的一般方法,具体内容请看:

.NET应用迁移到.NET Core(一)

.NET应用迁移到.NET Core(二)风险评估

.NET应用迁移到.NET Core(三)从商业角度看移植过程

今天给大家展示一个真实的项目的调查案例,一个轻量级的.NET 工作流引擎移植到.NET Core平台的调查案例,你也可以参照这篇案例进行迁移前的项目调查工作。

该调查问卷可以作为移植技术的一个指南,并且据此还可以提出其他一些问题。该问卷中的客户指的是一个要移植到 .NET Core 的内部或外部部门。

1、 你当前的应用程序开发平台是什么?

该问题是关于开发待移植 .NET 应用程序的开发平台。这里不假设开发平台和应用程序部署的平台是相同的。这留在下一个问题中。

Windows 7 + IIS 7.5 + .NET Framework 4.5 +Redis 2.4 + SQL Server 2008 R2

2、 该应用程序当前运行的平台是什么?

移植工程师需要知道待移植的应用程序当前运行的平台。

Windows 2008 R2 SP1 + IIS 7.5 + .NETFramework 4.5 + Redis 2.4 + SQL Server 2008 R2

3、 除了开发平台外,该应用程序是否还在其他平台上部署过?如果部署过,它运行的平台版本是什么 ?

问此问题可以让你知道应用程序的可移植性,看它是否移植到其他平台上。不过有一点需要注意:即使应用程序曾移植到其他平台上,它的目标平台可能也是比较老的版本。

没有在其他平台部署过。

4、 描述应用程序使用的系统信息,以及需要的驱动程序在 Linux 平台上是否可用。

确定 Linux 能够满足应用程序对平台的依赖。

系统信息:

  • .NET Framework 对应的 Linux 平台上有 Mono 和 .NET Core 两大平台

  • Redis 已经是在 Linux 平台上运行

  • Web 服务器 IIS 对应 Linux 平台上有 Jexus(Mono) 和 Apache/Nginx + Kestrel

  • SQL Server 在 Linux 平台上存在但是还是预览版,可以迁移到 MySQL

  • Entity Framework 6.1 和 Entity Framework Core 本身就是跨平台的,支持在 Linux 平台上访问 SQL Server

  • ServiceStack.Redis 也是支持 Mono 和 .NET Core

  • Owin 服务器在 Linux 平台上有 Jexus 支持 和 .NET Core 的支持

  • ASP.NET Web API 2.2 Linux 平台上有 Mono 4.6 支持,也可以迁移到 .NET Core

  • Windows 服务可以迁移到 Linux 的后台服务,可以 Topshelf 改造或者是迁移到 .NET Core 控制台应用,使用 Linux 系统服务或者是 Supervisorctl 运行

  • 站点使用的 ASP.Net MVC 在 Linux 上 Mono 4.6 支持,或者迁移到 .NET Core

1、 请详细描述应用程序及其结构。

在这里,用户可以描述应用程序的结构,并尽可能地包括结构图。应用程序的所有组件都要描述。如果有的话,该问题也应该会让你知道应用程序运行的框架。大部分的 .NET 应用程序运行在产品相关的框架上,例如 IIS 、 windows 服务和 WCF 服务。也就是说,需要你处理 .NET Core 可能不支持的某个具体的框架。

HRCommFlow 应用包括 2 部分:对外的 API 服务 和 Web 站点。

对外服务的 API 服务使用 ASP.NETWeb API ,使用 Windows 服务自宿主。使用的组件如下:

应用框架 组件 备注
ASP.NET Web API System.Web.Http
System.Web.Http.Owin
Microsoft.Owin.Host.HttpListener
EntityFramework 访问 SQL Server
Newtonsoft.Json Json
ServiceStack.Redis 访问 Redis
Tencent.OA.Framework 访问组织机构信息
ExpressionEvaluator
System.ServiceProcess

Web 站点使用 ASP.NET MVC 4 , 使用 IIS 宿主

应用框架 组件 备注
ASP.NET MVC Microsoft.AspNet.Mvc
Microsoft.AspNet.Razor
EntityFramework 访问 SQL Server
Newtonsoft.Json Json
Tencent.OA.Framework 访问组织机构信息
ExpressionEvaluator
System.ServiceProcess

2、 该应用程序有哪些不同组件?请给出各组件的名称和版本号。

该问题让你细分应用程序的结构,把应用程序细分成不同的组件。也就是说,可以把整个移植工作分成多个独立的任务。

组件名称 版本号 是否公开源代码
System.Web.Http 4.0.0.0
System.Web.Http.Owin 5.2.3.0
Microsoft.Owin.Host.HttpListener 3.0.0.0
EntityFramework 6.1.3
Newtonsoft.Json 6.0.8
ServiceStack.Redis 3.9.71.0
Tencent.OA.Framework 1.0.0.0
ExpressionEvaluator 2.0.4.0
System.ServiceProcess 4.0.0.0
Microsoft.AspNet.Mvc 4.0.30506.0
Microsoft.AspNet.Razor 2.0.30506.0

3、 那些组件需要移植,那些不需要?请包含版本号。

客户需要告诉你那些需要移植,那些不需要。

组件名称 版本号 移植到 Mono 移植到 .NET Core
System.Web.Http 4.0.0.0 不需要 不需要
System.Web.Http.Owin 5.2.3.0 不需要 不需要
Microsoft.Owin.Host.HttpListener 3.0.0.0 不需要 不需要
EntityFramework 6.1.3 不需要 不需要
Newtonsoft.Json 6.0.8 不需要 不需要
ServiceStack.Redis 3.9.71.0 不需要 不需要
Tencent.OA.Framework 1.0.0.0 需要 需要
ExpressionEvaluator 2.0.4.0 需要 需要
System.ServiceProcess 4.0.0.0 不需要 不需要
Microsoft.AspNet.Mvc 4.0.30506.0 不需要 不需要
Microsoft.AspNet.Razor 2.0.30506.0 不需要 不需要

4、 待移植的应用百分之多少是用下列编程语言编写 ?

  • Java

  • C#

  • F#

  • C

  • C++

  • 汇编语言

  • Visual Basic

  • IronPython/IronRuby

  • Powershell

通过询问应用程序使用了什么语言及其所占的比重,来确定应用程序的复杂度。

100% 使用 C# 语言编写

5、 粗略估计一下各语言所占的代码行数。

这是对问题 4 的另外一种问法,从不同的角度提出问题,常常能找到互相矛盾的地方,这就需要公开讨论,从而能够把项目调查清楚。

代码数量大概是 3500 行。

6、 对于 .NET 应用程序:使用了 P/Invoke 来链接特有的库了吗?请描述之。

明确待移植的应用程序的复杂度。多数情况下,非 100% 纯 .NET 编写的应用程序,都需要平台相关的例程,这些例程只能用固有的语言来处理,例如 C 语言。请注意这些平台相关的代码,往往它需要花费较多的时间来移植。

没有

7、 应用程序用了操作系统内核模块了吗?如果有,请描述之。

明确待移植的应用程序的复杂度。如果应用程序使用的操作系统内核模块和例程是不可移植的,就需要花费较多时间转换成目标平台上对应的例程。

没有

8、 该应用程序是 2D/3D 的图形应用程序吗?请描述之。

明确待移植的应用程序的复杂度。确认 .NET Core 上存在兼容的图形工具和开发工具,无论是系统默认提供的或者是第三方发行商提供的。

没有

9、 应用程序使用了消息队列、共享内存、信号或者信号量吗?请描述之。

上述内容大部分能够方便的移植到 .NET Core 上。需要确认移植到 .NET Core 后,能够使原来期望的行为。

没有

10、 应用程序或其中的组件,是多线程的吗?如果是,使用的是那种线程库 ? 应用程序依赖开发平台特有的线程属性吗?

Linux 支持多种线程库,但是现在以及将来的 Linux 发行版中,符合标准的线程库是 NPTL ( Native Posix Threads Library )实现。

组件没有多线程,也没有依赖开发平台特有的线程属性。

11、 应用程序的某些操作提前假设某种特定的字节顺序吗?这在移植过程会成为问题吗?

该问题是关于应用程序的 “ 大小端 ” ( Littleendian , Big endian )问题。大部分 .NET 移植到 .NET Core 的目标平台都是 Intel 平台,该平台是小端的。也有可能要把 .NET 程序移植到 RISC 类的大端平台。假设具体的大小端代码是不可移植的,并且如果移植不正确会导致不易察觉的错误。更糟糕的是,这些错误在移植时不会暴露出来,只会在系统测试的时候会突然出现问题,并且很难找到问题的根源。

没有假设字节顺序问题, .NET Framework 帮助我们解决这个问题

12、 开发平台使用的是那种编译器版本?

  • C# ( 什么版本? )

  • VB.NET( 什么版本? )

  • F#( 什么版本? )

  • 平台特有编译器( Visual C++ )

  • 其他(请列出)

明确待移植的应用程序的复杂度。如果待移植的应用程序用的是 C#/VB.NET 或者 F# 编译器,则移植到 Linux 上会简单一些,因为 .NET Core 和 .NET 使用相同的编译器。如果用了 windows 平台特有编译器编译的应用程序, C++ 应用程序比 C 程序较难移植,应用程序可能使用了 C++ 特性,例如模板。因为 C++ 标准在不同厂商的编译器上实现不同,移植这种类型的代码比简单的 C/C++ 代码要花费更多的时间。

使用 C# 编写的应用程序, .NET Core 和 .NET 使用相同的编译器, Mono 也是兼容的编译器。

13、 除了开发环境,应用程序还依赖其他的调试工具吗?例如内存泄漏调试器、性能分析工具、异常处理等。

这又回到了调查和分析依赖关系。 Linux 上可能有,也可能没有所需的第三方工具,这需要调查。谁提供许可?谁负责获取这些工具?如果需要第三方支持,谁来提供支持?

没有依赖其他的调试工具。

14、 该应用程序是基于 Socket 的吗?如果是,它使用了 RPC 吗?请描述之。

虽然 Linux 支持标准的 socket 和 RPC 语义,但该问题的目的是确认程序的可移植性,比如 .NET 使用了 WCF 的 RPC , .NET Core 仅支持 WCF 的客户端访问,对于系统移植就很困难。问该问题可以搞清楚客户是否在应用程序里实现了不可移植的结构。该问题也可以引出其他问题,例如在测试阶段需要怎么样的配置。

没有使用 RPC ,使用的是 HTTP Web API ,依赖的组件 Tencent.OA.Framework 依赖于 WCF的客户端访问,需要移植到 HTTP Web API 接口访问。

15、 应用程序使用了第三方软件组件吗(数据库工具、应用程序服务器或其他中间件)?如果是,使用了哪些组件?

每一个第三方软件组件都会增加移植的复杂度。如果使用了任何第三方组件,都需要询问试了该组件的那个版本以及 .NET Core 上是否存在对应版本。第三方组件可能需要额外的时间去学习,甚至是配置或编译。

应用程序使用了第三方组件,

组件名称 版本号 Mono 是否存在对应版本 .NET Core 是否存在对应版本
System.Web.Http 4.0.0.0 存在 存在
System.Web.Http.Owin 5.2.3.0 存在 不存在
Microsoft.Owin.Host.HttpListener 3.0.0.0 存在 不存在
EntityFramework 6.1.3 存在 存在
Newtonsoft.Json 6.0.8 存在 存在
ServiceStack.Redis 3.9.71.0 存在 存在
Tencent.OA.Framework 1.0.0.0 存在 不存在
ExpressionEvaluator 2.0.4.0 存在 不存在
System.ServiceProcess 4.0.0.0 存在 存在
Microsoft.AspNet.Mvc 4.0.30506.0 存在 存在
Microsoft.AspNet.Razor 2.0.30506.0 存在 存在

16、 应用程序时如何交付和安装的?使用标准的打包工具吗?安装脚本也需要移植吗?

Linux 上一个标准的打包工具是 RPM 。 RPM 会在其他章节讲述。明确客户是否需要移植应用程序打包部分的内容。

使用 XPlat 模式,没有使用打包工具,直接拷贝,部署运行。

17、 应用程序或组件是 64 位的吗?有组件需要移植成 64 位的吗?

随着 64 位平台和操作系统的普及,该问题是要知道应用程序需要运行在什么体系结构的平台上。通过现代的编译器,大部分 32 为应用程序都可以轻松移植到 64 位环境上。需要考虑的一点就是移植和调试可能需要较长的时间。

应用程序都是 64 位的,不存在组件需要移植成 64 位。

1、 应用程序当前支持什么数据库?请包括版本号。

现在几乎所有的企业应用程序都需要后台数据库。确认应用程序所需的数据库在 Linux 上可用非常重要。数据库产品以及版本之间的差别会导致增加很多移植工作。

应用程序支持的 SQLServer 2008 R2 ,目前在 Linux 上处于预览版,需要移植到 MySQL 。

2、 移植后的应用程序期望运行在什么数据库上?

除了问题 1 外,客户希望移植后的应用程序运行在 Linux 平台的什么数据库上?

希望移植后应用程序运行在 Linux 的 MySQL 5.6 上。

3、 应用程序使用了非关系数据库或私有数据库吗?

现在还有很多应用程序使用 NoSQL 数据库,幸运的是大部分 NoSQL 数据库都运行在 Linux 上。任何私有数据库都需要移植到 Linux 上。确认运行数据库的代码在 Linux 上可用,这也是调查阶段工作的一部分。

应用程序使用了 NoSQL 数据库 Redis , Redis 在 Linux 上运行良好。

4、 应用程序是如何与数据库通信的?

  • 编程语言(例如 C#,VB.NET 等)

  • 数据库接口(例如 ODBC , ADO.NET , Entity Framework )

确认所用的编程语言或接口在 Linux 上可用,确认是否由第三方厂商提供。

应用程序使用了 Entity Framework 访问 SQL Server ,微软官方提供。

5、 应用程序需要使用扩展的数据类型吗( XML 、 audio , binary 、 video )?

这个问题主要用来评估移植小组需要具备的技能。

应用程序使用 Json 数据类型。

1、 应用程序在目标平台上的正式可用日期是那天?

该问题是要明确在制定移植进度计划时,是否有商业目标需要考虑。

需要在 2017 年春节前上线运营。

2、 应用程序在目标平台上的移植工作已经开始了吗?

这可以帮助评估在正式开始之前发现的复杂度问题。

没有开始。

3、 估计得移植复杂度是什么(低、中还是高)?

需要仔细分析对该问题的回答。现在很可能有一些新的因素在以前的移植经历中没有完全认识到。

移植复杂度适中,都是用 C# 语言编写的应用组件,需要移植的第三方组件也比较少,而且都有源代码。

4、 在确定复杂度级别时,考虑了什么因素?

以前移植工作的任何信息都需要评估,并且与将来的 Linux 平台移植工作进行对比。

5、 该应用程序曾移植到其他平台上吗?用了多长时间?需要多少资源?遇到过什么问题?

该问题试图把以前的移植工作和 .NETCore 移植进行比较。这只有在移植工程师的技术领导同时具有 Windows 平台和 Linux 平台移植经验的情况下,才会有用。

没有

6、 你是怎样粗略估计项目移植时间和所需资源的?

应用程序或某些部分可能曾移植到其他平台上,知道向那些平台移植所花的时间会有些帮助。从那些移植过程得出的经验和教训会派上用场。吸取这些教训可以帮助你避免向 .NET Core 移植时重蹈覆辙。

1、 请描述接收测试的环境配置。

服务器配置 用途 环境
tLinux 2.2/CentOS 7.2 API 服务器 Mono 4.6/Jexus/.NET Core 1.1/Nginx
tLinux 2.2/CentOS 7.2 数据库服务器 MySql 5.6+
tLinux 2.2/CentOS 7.2 Redis 服务器 Redis 3.2
Windows Server 2008 R2 原 API 服务器 / 数据库服务器 SQL Server 2008R2

2、 单元测试需要什么样的网络和数据库配置?

3、 移植测试需要多少时间和资源?

4、 是否已经建立了测试脚本和性能度量标准?

5、 需要运行一些基准测试来进行比较吗?

6、 性能数据在当前平台上可用吗?

7、 最后执行性能测试是什么时间?

所有测试相关的问题都适用于软件程序在 Linux 平台上的测试。问这些问题还可以引出其他一些与移植测试脚本和测试工具有关的问题,而这些可能会增加整个项目的风险和时间。要重点关注客户对问题 1 的回答。问题 1 和接收标准有关,这些标准需要各方在移植开始之前都同意。一个接收标准的例子是:模块 A 和 B 应该通过测试用例 c 和 d ,并且没有错误。当达到测试标准后,移植可以说是完成了,正式的 QA 测试接着就可以开始了。

1、 根据你希望的情况,请选择下面的一项或多项:

  • 必要的话,将会给移植工程师提供一些技术帮助。

  • 客户负责获取第三方工具许可和技术支持。

  • 其他(请描述)。

可以在这里增加你认为需要客户考虑的其他事项。有些问题可能是关于员工培训或测试应用程序等。

2、 项目需要什么硬件?

该问题是要确认是否会用到现有的硬件或额外的硬件,以用于移植、测试、培训,以及必要的支持等。

尽管上述问卷已经比较全面,但是它不应该是调查所依赖的唯一基础。调查还应该包括对应用程序源代码的实际检查。软件程序的文档也需要检查,以便用户能够从中了解到需要的应用程序信息。

.NET社区新闻,深度好文,微信中搜索 dotNET跨平台 或扫描二维码关注

.NET 4.5+项目迁移.NET Core的问题记录

这几天试着把目前的开发框架迁移到新的.net core平台,中间遇到的问题在这里简单记录一下。

迁移过程遇到的最大的问题IOC容器。我目前使用的IOC容器Castle Windsor还没有.net core版本的实现,虽然core本身提供有注入功能,但我想在代码上尽量保持与.NET Framework的兼容,最后还是选择使用第三方容器Autofac,不过在容器上层做了隔离,也就是可以随时替换掉IOC。
关于第三方容器接管.net core的注入实现,官方文档有介绍,也可以参考autofac的实现
https://github.com/autofac/Autofac.Extensions.DependencyInjection

第二个问题是.net core没有App Domain,不能像以前那样方便的加载项目程序集,替换方法是手工扫描BIN目录,再通过AssemblyLoadContext加载到内存。不过遇到一个问题是在加载入口项目DLL的时候,会提示无法加载,目前我是通过Assembly.GetEntryAssembly()后简单粗暴的排除掉。哪位朋友知道有更好的方法,劳烦告知一下。

其他方式:
var assemblies = DependencyContext.Default.RuntimeLibraries;//需要引用程序集

第三个问题是很多Type的反射接口不存在了,可以通过Type.GetTypeInfo()获取,不过要额外引用扩展库。

第四个问题是在发布到服务器IIS之后,出现下面的异常:

HTTP Error 502.5 - Process Failure

Common causes of this issue:
The application process failed to start.
The application process started but then stopped.
The application process started but failed to listen on the configured port.

WINDOWS系统日志:

Failed to start process with commandline '"dotnet" .\Portal.dll', ErrorCode = '0x80070002'.

首先说一下,在部署IIS的时候,需要在windows server上安装文件DotNetCore.1.0.1-WindowsHosting.exe,它会在IIS上添加一个aspnetcore module,托管net core的运行。新建站点后将应用程序池修改为无托管模式即可。就在这个地方我遇到上边的错误,页面一直提示502无法打开,端口和编译平台都没有问题。
网上找了很多方法试过后都没有效果,最后感觉还是hosting的问题,而且我在安排hosting文件的时候的确报过一次错,后来是用右键管理员运行安装完成的,然后到iis模块下果真没有找到aspnetcore module。
卸载后重装又出现了第一次的问题,安装失败。最后在stackoverflow上看到一句话

Make sure when you install the DotNetCore WindowsHosting you have access to the internet because the installer download the VS 2015 resist x64 as dependency.

VS 2015 resist x64 - http://download.microsoft.com/download/8/c/b/8cb4af84-165e-4b36-978d-e867e07fc707/vc_redist.x64.exe

果断下载安装后再运行WindowsHosting就没再报错了,这里还需要重启一下服务器。

https://aka.ms/dotnetcore_windowshosting_1_1_0

手指在键盘上飞快的敲下那一串域名,点击Enter,那一刻的感觉好极了@@

作者出处Ronli (Http://Ronli.cnblogs.com/)

转载声明:自由转载,谢绝演绎。请保留署名、链接及更新时间

更新链接:文章内容受撰文时个人水平局限,可能存在的错误及不准确之处谢谢指正;

请保留文章链接和更新时间,方便最终读者甄别。

ASP.NET Core 1.1 简介

ASP.NET Core 1.1 于2016年11月16日发布。这个版本包括许多伟大的新功能以及许多错误修复和一般的增强。这个版本包含了多个新的中间件组件、针对Windows的WebListener服务器、Razor视图编译以及Azure相关的特性。要将现有项目更新到ASP.NET Core 1.1 ,您需要执行以下操作:

1. 下载并安装更新的.NET Core 1.1  SDK
2. 按照.NET Core 1.1 升级公告(下一节介绍)中的说明将项目更新为使用.NET Core 1.1
3. 更新您的ASP.NET Core包依赖项以使用新的1.1.0 版本

注意:要在Visual Studio中使用NuGet包管理器将包更新到1.1 ,您需要从nuget.org下载并安装用于nuget  3.5 。你现在应该准备试试1.1!

新的中间件组件和增强

在这个版本中,我们能够在特定的控制器或action中使用中间件组件。组件可以借助新的MiddlewareFilterAttribute担当MVC资源过滤器的角色。例如,响应压缩和缓存这样的功能可以配置在特定的action或控制器中,而不是配置在整个应用的级别上。

在之前的几个版本中,URL重写(URL rewriting)就已经成为IIS的一项特性了,它是作为一个http模块来实现的。在这个预览版本中,URL重写作为一个中间件组件重新回归了。这个组件可以配置为使用IIS标准的XML格式化规则、Apache Mod_Rewrite语法,也可以直接使用Web应用中的C#方法。

ASP.NET Core 1.1还带来了两个新的中间件,也就是响应缓存(response caching)响应压缩(response compression)。响应缓存中间件会作为ASP.NET MVC中OutputCacheAttribute的继任者。

URL重写中间件

通过可以使用IIS标准XML格式化规则,Apache Mod_Rewrite语法或一些编码到您的应用程序中的一些简单的C#方法配置的中间件组件将URL重写功能带到ASP.NET Core。这允许将设计用于客户端消耗的公共URL空间映射到中间件流水线所需的下游组件的任何表示,以及根据模式将客户端重定向到不同的URL。

例如,您可以通过重写对http://example.com的任何请求来确保规范主机名,而在重写规则运行后为所有内容重写http://www.example.com。另一个示例是将所有请求重定向到http://example.com到https://example.com。您甚至可以配置URL重写,以便应用这两个规则,并且对example.com的所有请求始终重定向到SSL并重写为www。

我们可以通过添加对Microsoft.AspNetCore.Rewrite包的Web应用程序的引用来开始使用此中间件。这允许我们在我们的重写器的Startup.Configure方法中添加一个调用来配置RewriteOptions:

using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Rewrite;

namespace MyApplication {

    public class Startup {

        public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
        {

            var options = new RewriteOptions()
                .AddRedirect("(.*)/$", "$1")                    // 使用正则表达式重定向
                .AddRewrite(@"app/(\d+)", "app?id=$1", skipRemainingRules: false) // 基于正则表达式重写
                .AddRedirectToHttps(302, 5001)                  // 重定向到其他端口并使用HTTPS
                .AddIISUrlRewrite(env.ContentRootFileProvider, "UrlRewrite.xml")        // 使用IIS UrlRewriter规则进行配置
                .AddApacheModRewrite(env.ContentRootFileProvider, "Rewrite.txt");       // 使用Apache mod_rewrite规则进行配置
            app.UseRewriter(options);
        }
        
        // Other Code
    
    }
    
}
正如你所看到的,我们可以用不同的规则强制重写和重定向。
  • Url Redirect将HTTP 301 Moved Permanently状态代码发送到具有新地址的客户端
  • Url Rewrite为HTTP管道中的后续步骤提供了一个不同的URL,欺骗它认为请求了不同的地址。

响应缓存中间件

通过将Microsoft.AspNetCore.ResponseCaching和Microsoft.Extensions.Caching.Memory包添加到应用程序中,现在可以在应用程序中激活与之前的ASP.NET版本的OutputCache功能类似的响应缓存。 您可以在Startup.ConfigureServices方法中将此中间件添加到应用程序,并从Startup.Configure方法配置响应缓存。 对于示例实现,请查看ResponseCaching存储库中的演示。

响应压缩中间件

现在,您可以将GZipCompression添加到ASP.NET HTTP管道,如果您希望ASP.NET执行压缩,而不是前端Web服务器。 此中间件在Microsoft.AspNetCore.ResponseCompression包中提供。 您可以在Startup.cs类中使用具有以下语法的最快压缩级别添加简单的GZipCompression:

public class Startup {

    public void ConfigureServices(IServiceCollection services) 
    {

        services.AddResponseCompression();
        
    }

    public void Configure(IApplicationBuilder app) 
    {

        app.UseResponseCompression();

        // Other code

    }
}

还有其他可用于配置压缩的选项,包括指定自定义压缩提供程序的功能。

Razor视图编译

在ASP.NET MVC之前的版本中,有一种预编译Web站点的方式,这样的话,视图编译就可以在部署阶段执行,而不是在运行期。通过这种方式,能够减少部署后首次加载页面所造成的延迟。ASP.NET Core 1.1重新带回了预编译Razor视图的功能。这个视图编译器要添加到应用的project.json文件的“tools”部分,并且要带有对工具包的引用。在运行package restore之后,dotnet razor-precompile命令就可以预编译razor视图了。

将视图组件用作标签助手

现在,您可以使用Tag Helper语法从视图中调用View组件,并在Visual Studio中获得IntelliSense和Tag Helper工具的所有优点。 以前,要从视图调用View组件,您将使用Component.InvokeAsync方法,并使用匿名对象传递任何View组件参数:

@await Component.InvokeAsync("Copyright", new { website = "example.com", year = 2016 })
相反,您现在可以像获取任何标记助手一样调用View组件,同时获取View Component参数的Intellisense:

要启用将View组件调用为标签助手,只需使用@addTagHelpers指令将View组件添加为标签助手:
@addTagHelper "*, WebApplication1"

中间件作为MVC过滤器

中间件通常位于全局请求处理管道中。 但是如果你想将中间件只应用于特定的控制器或操作呢? 您现在可以使用新的MiddlewareFilterAttribute将中间件应用为MVC资源过滤器。 例如,您可以将响应压缩或缓存应用于特定操作,也可以使用基于路由值的请求文化提供程序,使用本地化中间件为请求建立当前文化。

要使用中间件作为过滤器,您首先使用Configure方法创建一个类型,该方法指定要使用的中间件管道:

public class LocalizationPipeline {

    public void Configure(IApplicationBuilder applicationBuilder) 
    {
    
        var supportedCultures = new[]
        {
            new CultureInfo("en-US"),
            new CultureInfo("fr")
        };

        var options = new RequestLocalizationOptions {
         
            DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        };
        options.RequestCultureProviders = new[] { new RouteDataRequestCultureProvider() { Options = options } };

        applicationBuilder.UseRequestLocalization(options);
        
    }
}

然后,您可以使用MiddlewareFilterAttribute将该中间件流水线应用于控制器操作或全局:

[Route("{culture}/[controller]/[action]")]
[MiddlewareFilter(typeof(LocalizationPipeline))]
public IActionResult CultureFromRouteData() 
{

  return Content($"CurrentCulture:{CultureInfo.CurrentCulture.Name},CurrentUICulture:{CultureInfo.CurrentUICulture.Name}");

}

虽然视图的razor语法提供了不需要编译器的灵活开发体验,但在某些情况下,您不希望在运行时解释razor语法。 您现在可以预先编译应用程序引用的Razor视图,并使用应用程序部署它们。 您可以在project.json的“tools”部分中使用包引用“Microsoft.AspNetCore.Mvc.Razor.Precompilation.Tools”将视图编译器添加到应用程序。 运行程序包恢复后,您可以执行“dotnet razor-precompile”来预编译应用程序中的剃刀视图。

 

针对Windows的WebListener服务器

WebListener是构建在Windows Http Server API之上的服务器。WebListener提供了依赖于平台的特性,比如Windows authentication、端口共享(port sharing)、结合SNI的HTTPS、基于TLS的HTTP/2(Windows 10)、直接的文件传输以及WebSockets的响应缓存(Windows 8)。

用于Windows的WebListener服务器

WebListener是直接在Windows Http Server API之上运行的服务器。 WebListener提供了利用Windows特定功能的选项,如支持Windows身份验证,端口共享,带有SNI的HTTPS,TLS的HTTP / 2(Windows 10),直接文件传输和响应缓存WebSockets(Windows 8)。 在Windows上,您可以使用此服务器而不是Kestrel,通过引用Microsoft.AspNetCore.Server.WebListener包而不是Kestrel包,并将WebHostBuilder配置为使用Weblistener而不是Kestrel:

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseStartup<Startup>()
        .UseWebListener(options =>
        {
            options.ListenerSettings.Authentication.Schemes = AuthenticationSchemes.None;
            options.ListenerSettings.Authentication.AllowAnonymous = true;
        })
        .Build();

    host.Run();
}

您可以在其GitHub存储库中找到演示使用WebListener的其他示例。

与作为此版本的一部分的其他软件包不同,WebListener正以1.0.0和1.1.0的形式提供。 1.0.0版本的包可用于生产LTS(1.0.1)ASP.NET Core应用程序。

Azure相关的特性

AzureAppServicesIntegration包允许发送日志到Azure App Service中。要写入的所有日志信息都会使用ILogger/ILoggerFactory抽象,在Azure门户的App Service配置中,Diagnostics Logs区域设置了这些日志将会写入到什么位置中。

AzureKeyVault包带来了一个针对Azure Key Vault的配置提供者(configuration provider )。这样的话,就允许我们在应用启动的时候从Key Vault secrets中获取配置,并将其放在内存之中,从而能够使用正常的ASP.NET Core配置抽象来访问配置数据。

ASP.NET Core引入了DataProtection,它提供了加密相关的API。这个预览版本包含了两个包,允许将数据保护的key(Data Protection key)存储到Azure StorageRedis中。这样的话,能够跨多个Web站点实例来共享key,也能够在负载均衡的场景下跨多台服务器进行共享。

Azure App Service日志记录提供程序

Microsoft.AspNetCore.AzureAppServicesIntegration包允许您的应用程序利用App Service特定的日志记录和诊断。 使用ILogger / ILoggerFactory抽象编写的任何日志消息将转到门户中App Service配置的“诊断日志”部分中配置的位置(请参阅屏幕截图)。

用法:

添加对Microsoft.AspNetCore.AzureAppServicesIntegration包的引用,并调用Program.cs中的UseAzureAppServices方法。

public static void Main(string[] args) 
{

  var host = new WebHostBuilder()
    .UseKestrel()
    .UseAzureAppServices()
    .UseStartup<Startup>()
    .Build();
  
  host.Run();
  
}

注意:UseIISIntegration不在上述示例中,因为UseAzureAppServices包括它,如果您有两个调用,但不显式调用UseIISIntegration不应该不会伤害您的应用程序。

添加UseAzureAppServices方法后,您的应用程序将遵守Azure应用程序服务设置的诊断日志部分中的设置,如下所示。 如果更改这些设置,例如,从文件系统切换到blob存储日志,您的应用程序将自动切换到记录到新位置,而不重新部署。

Azure密钥库配置提供程序

Microsoft.Extensions.Configuration.AzureKeyVault包为Azure密钥库提供配置提供程序。 这允许您从应用程序启动时从密钥保险库秘密检索配置并将其保存在内存中,使用普通的ASP.NET Core配置抽象来访问配置数据。

提供者的基本用法是这样的:

var builder = new ConfigurationBuilder();
    .AddJsonFile("settings.json")
    .AddKeyVault(
        "<vault uri>", //要从中检索密钥的密钥库的URI
        "<clientId>", //要用于检索密钥的客户端ID。
        cert //用于使用Azure AD进行身份验证的x509证书
    )

 

有关如何添加Key Vault配置提供程序的示例,请参阅此处的示例:

https://github.com/aspnet/Configuration/tree/dev/samples/KeyVaultSample

Redis和Azure存储数据保护密钥库

Microsoft.AspNetCore.DataProtection.AzureStorage和Microsoft.AspNetCore.DataProtection.Redis软件包允许将数据保护锁分别存储在Azure存储或Redis中。 这允许在网站的多个实例之间共享密钥,以便您可以例如在运行ASP.NET Core应用程序的多个负载平衡服务器上共享认证cookie或CSRF保护。 由于数据保护在幕后用于MVC中的一些事情,极有可能一旦你开始向外扩展,你将需要共享钥匙圈。 在这两个包之前共享密钥的选项是使用网络共享与基于文件的密钥存储库。

Azure示例

services.AddDataProtection()
  .AddAzureStorage(“<blob URI including SAS token>”);

Redis示例

// Connect
var redis = ConnectionMultiplexer.Connect("localhost:6379");

// Configure
services.AddDataProtection()
  .PersistKeysToRedis(redis, "DataProtection-Keys");

注意:当使用非持久性Redis实例时,使用Data Protection加密的任何内容将无法在实例重置后解密。 对于默认的认证流,这通常只是意味着用户被重定向到再次登录。 但是,对于使用Data Protections Protect方法手动加密的任何内容,您将无法完全解密数据。 因此,当手动使用Data Protection的Protect方法时,不应使用不持久的Redis实例。 数据保护针对短暂数据进行了优化。

备注

本文是针对ASP.NET Core 1.1 的简介,希望本文对你有所帮助

欢迎大家关注微信号opendotnet,微信公众号名称:dotNET跨平台。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码)

云计算之路-阿里云上:数据库连接数过万的真相,从阿里云RDS到微软.NET Core

在昨天的博文中,我们坚持认为数据库连接数过万是阿里云RDS的问题,但后来阿里云提供了当时的数据库连接情况,让我们动摇了自己的想法。

帐户 连接数
A 4077
B 3995
C 741
D 698
E 519

上面这5个帐户产生了10030个数据库连接,当看前4个帐户(产生了9511个连接)的名称时,我们打了一个寒颤 —— 这些都是运行 Linux 上的 ASP.NET Core 站点。。。这不是巧合,其中必有蹊跷。

随后,我们观察了主备库切换后的 RDS 中数据库连接情况。有一个运行在 Linux 上的 ASP.NET Core 站点,用了3台服务器,却产生了1528个数据库连接。

SELECT * FROM sys.sysprocesses 
WHERE loginame='xxx'

重启其中1台服务器上的站点,连接数立马从1528降到了391。什么情况?数据库连接池发飙了?

继续观察,当前数据库中大量的连接都是由运行在 Linux 上的 ASP.NET Core 站点产生的,而且会随着时间的推移保持增长。

数据库连接泄漏了,这还是第1次遇到!可我们在 APS.NET Core 应用中所有的数据库操作都用的是Entity Framework Core,不存在没有及时关闭数据库连接的情况,唯一可以怀疑的对象是在 System.Data.SqlClient 中实现的 ADO.NET 数据库连接池。

数据库连接池究竟出什么状况了?我们在数据库连接字符串中没有另外设置连接池,用的是默认设置(Min_Pool_Size = 0; 与 Max_Pool_Size = 100;)。而且更奇怪的是 Max_Pool_Size 的限制没起作用,不然只会报下面的错误,不会连接数一直增长。

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.

我们想来想去,唯一能想得通的解释是 .NET Core 的数据库连接池发生了这样的状况 —— 连接池中已经创建的连接无法被重用,不仅如此,而且它们直接被 SqlClient 给无视了,都没有被计算在 Pool Size 中,所以根本触发不了 Max_Pool_Size 的限制,造成连接无限制,任由 SqlClient 建。更要命的是,这些被无视的连接却一直在保持着与数据库的连接。于是,连接泄露成了命中注定。

在有了这个唯一想得通的猜测后,我们今天开始在测试环境中进行验证。

部署一个 ASP.NET Core 站点,创建一个专用数据库连接帐户,然后用下面的 SQL 语句查看数据库连接是否被重用,同时在测试服务器用 tcpdump 进行抓包,并且分别用阿里云 RDS 与我们自己搭建的 SQL Server 服务器进行测试。

SELECT * from sys.sysprocesses where loginame='测试专用帐户'

如果连接池正常工作,第1次访问,新建所需的数据库连接;第2次访问同样的页面,应该重用已有的数据库连接,不会创建新的数据库连接。

开始测试时,不管连接阿里云 RDS 还是我们自己的 SQL Server,连接池都工作正常,连接能被重用。

后来分析了一下,虽然生产环境中连接数一直在增长,但增长速度不是很快,可能问题的发生需要一定的时间间隔,或许连接闲置超过一定时间之后才不会被重用。

于是,我们间隔了10分钟左右进行访问测试,问题重现了!比如其中的一次测试,同一个页面第1次访问,产生了5个连接;过10分钟左右再访问,会新建3个连接变成8个连接;再过10分钟左右访问,连接增长到11个。这种连接不能被重用的情况通过 tcp 抓包也可以看出来。如果在很短的时间内访问,连接数保持不变(连接被重用)。

这个问题不仅在阿里云 RDS (SQL Server 2008 R2)可以重现,而且在我们自己搭建的 SQL Server 2014 也能重现,问题的真相随之水落石出。

数据库连接数过万问题不是阿里云 RDS 的问题,而是 .NET Core 中 System.Data.SqlClient 的连接池在 Linux 上的实现问题,我们错怪了阿里云,轻信了微软。这是我们使用阿里云以来对阿里云最大的一次误会,这是我们 .NET Core 迁移过程中遇到的最大的一个坑。

为什么最近才出现这个问题?是因为我们最近将更多站点迁移到了 ASP.NET Core ,而且将之前一些跑在 Windows 上的 ASP.NET Core 站点切换到了 Linux 。

如何解决这个问题?我们会察看一下 System.Data.SqlClient 的实现代码,看能否找到实现层面的线索。阿里云会进一步验证这个问题,如果确认是微软实现上的问题,会与微软沟通解决。

【16:55 更新】

我们在 Windows 上进行对比测试发现,在 Windows 上连接池中闲置的数据库连接过段时间会被自动关闭,与上面 Linux 同样的测试场景,间隔10分钟后查看,数据库连接全消失了。

【18:18 更新】

感谢 @feiyun0112 在评论中提供的线索,2016年11月7日就有人发现了这个问题,并且在 github 上提交了 issue

【18:41 更新】

我们在应用中使用的 System.Data.SqlClient.dll 版本是 4.3.0,是在2016年11月5日生成的,正好在这个 issue 之前。

【20:56 更新-成功解决】

通过手动替换 System.Data.SqlClient.dll 文件解决了这个问题。操作步骤如下:

1)在 https://github.com/dotnet/corefx/releases 下载 .NET Core 1.1 得到 corefx-1.1.0.zip 文件并解压。

2)在 corefx-1.1.0 文件中运行 init-tools.cmd 命令安装 build 工具

3)用 VS2017 打开 corefx-1.1.0\src\System.Data.SqlClient 中的 System.Data.SqlClient.sln 解决方案

4)打开 SNITcpHandle.cs ,去掉 private readonly NetworkStream _tcpStream; 中的 readonly ,在 Dispose() 方法中添加如下代码:

if (_tcpStream != null)
{
    _tcpStream.Dispose();
    _tcpStream = null;
}

5)用 VS2017 以 Release 方式 build System.Data.SqlClient 项目。

6)将 corefx-1.1.0\bin\Unix.AnyCPU.Release\System.Data.SqlClient 文件夹中生成的 System.Data.SqlClient.dll 文件,在 git bash 中通过 scp 命令上传到 Linux 服务器上的 nuget 文件夹。

MINGW64 /c/Dev/GitHub/corefx-1.1.0/bin/Unix.AnyCPU.Release/System.Data.SqlClient
$ scp System.Data.SqlClient.dll root@ubuntu-server:~/.nuget/packages/system.data.sqlclient/4.3.0/runtimes/unix/lib/netstandard1.3
System.Data.SqlClient.dll      100%  708KB 176.9KB/s   00:04

7)登录 Linux 服务器重启 ASP.NET Core 站点

8)第一次访问,在数据库中看到了这些新建的连接,然后停止访问。。。等了5-6分钟,这些连接全部消失,和在 Windows 上的表现一致,连接泄露的问题搞定!

连接泄露引起的数据库连接数过万的问题,仅仅是因为少写了1行 Dispose 代码。

附:我们 build 出来的修复这个问题的 System.Data.SqlClient.dll

【23:15 更新】

更新 System.Data.SqlClient.dll 之后,效果是立竿见影!

如何一小时爬取百万知乎用户信息,并做简单的可视化分析?

一、使用的技术栈:

  • 爬虫:python27 +requests+json+bs4+time
  • 分析工具: ELK套件
  • 开发工具:pycharm

二、数据成果

三、简单的可视化分析

1.性别分布

  • 0 绿色代表的是男性 ^ . ^
  • 1 代表的是女性
  • -1 性别不确定

可见知乎的用户男性颇多。

WechatIMG2.jpeg

2.粉丝最多的top30

粉丝最多的前三十名:依次是张佳玮、李开复、黄继新等等,去知乎上查这些人,也差不多这个排名,说明爬取的数据具有一定的说服力。

粉丝最多的top30

3.写文章最多的top30

写文章最多的top30

四、爬虫架构

爬虫架构图如下:

爬虫架构图

说明:

  • 选择一个活跃的用户(比如李开复)的url作为入口url.并将已爬取的url存在set中。
  • 抓取内容,并解析该用户的关注的用户的列表url,添加这些url到另一个set中,并用已爬取的url作为过滤。
  • 解析该用户的个人信息,并存取到本地磁盘。
  • logstash取实时的获取本地磁盘的用户数据,并给elsticsearch
  • kibana和elasticsearch配合,将数据转换成用户友好的可视化图形。

五.编码

爬取一个url:

def download(url):
    if url is None:
        return None
    try:
        response = requests.get(url, headers={
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
            'authorization': 'your authorization '
        })
        print (response.content)
        if (response.status_code == 200):
            return response.content
        return None
    except:
        return None

解析内容:

def parse(response):
    try:
        print (response)
        json_body = json.loads(response);
        json_data = json_body['data']
        for item in json_data:
            if (not old_url_tokens.__contains__(item['url_token'])):
                if(new_url_tokens.__len__()<2000):
                   new_url_tokens.add(item['url_token'])
            if (not saved_users_set.__contains__(item['url_token'])):
                jj=json.dumps(item)
                save(item['url_token'],jj )
                saved_users_set.add(item['url_token'])

        if (not json_body['paging']['is_end']):
            next_url = json_body['paging']['next']
            response2 = download(next_url)
            parse(response2)

    except:
        print ('parse fail')

存本地文件:

def save(url_token, strs):
    f = file("\\Users\\forezp\\Downloads\\zhihu\\user_" + url_token + ".txt", "w+")
    f.writelines(strs)
    f.close()

代码说明:

  • 需要修改获取requests请求头的authorization。
  • 需要修改你的文件存储路径。

源码下载:点击这里,记得star哦!

六.如何获取authorization

  • 打开chorme,打开https://www.zhihu.com/,
  • 登陆,首页随便找个用户,进入他的个人主页,F12(或鼠标右键,点检查)
  • 点击关注,刷新页面,见图:

如何获取authorization

七、可改进的地方

  • 可增加线程池,提高爬虫效率
  • 存储url的时候我才用的set(),并且采用缓存策略,最多只存2000个url,防止内存不够,其实可以存在redis中。
  • 存储爬取后的用户我说采取的是本地文件的方式,更好的方式应该是存在mongodb中。
  • 对爬取的用户应该有一个信息的过滤,比如用户的粉丝数需要大与100或者参与话题数大于10等才存储。防止抓取了过多的僵尸用户。

八.关于ELK套件

关于elk的套件安装就不讨论了,具体见官网就行了。网站:https://www.elastic.co/

另外logstash的配置文件如下:

input {
  # For detail config for log4j as input,
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html

    file {
        path => "/Users/forezp/Downloads/zhihu/*"
    }


}
filter {
  #Only matched data are send to output.
}
output {
  # For detail config for elasticsearch as output,
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
 elasticsearch {
    action => "index"          #The operation on ES
    hosts  => "localhost:9200"   #ElasticSearch host, can be array.
    index  => "zhihu"         #The index to write data to.
  }
}

九、结语

从爬取的用户数据可分析的地方很多,比如地域、学历、年龄等等,我就不一一列举了。另外,我觉得爬虫是一件非常有意思的事情,在这个内容消费升级的年代,如何在广阔的互联网的数据海洋中挖掘有价值的数据,是一件值得思考和需不断践行的事情。最后,本文仅用作交流学习,一切数据归知乎所有。如果知乎告知我侵权,我会立刻删除本文。

http://www.jianshu.com/p/5e6415cb5c60

微信公众平台H5支付

值得注意的是openid值的获取, 直接贴代码这里输入代码`

    /**
     * 微信统一下单
     * 
     * @param fenpay
     * @param orderStr
     * @return
     */
    private String placOrder(int fenpay, String orderStr, String subject) {
        Object openid = WebUtils.getSessionAttribute("openid");
        if (openid == null) {
            throw new ServiceException("没有获得微信授权,不能使用微信支付");
        }
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        SortedMap<String, String> sm = new TreeMap<String, String>();
        // 添加三个固定的参数
        sm.put("appid", WeiXinUtil.APPID);
        sm.put("mch_id", WeiXinUtil.MCH_ID);
        sm.put("notify_url", WeiXinUtil.NOTIFY_URL);
        sm.put("trade_type", WeiXinUtil.TRADE_TYPE);
        sm.put("nonce_str", RandomStringGenerator.getRandomStringByLength(8));
        sm.put("body", subject);
        sm.put("out_trade_no", orderStr);
        sm.put("total_fee", String.valueOf(fenpay));
        sm.put("spbill_create_ip", "127.0.0.1");
        // 现在写死的
        // sm.put("openid", "oMEZLt3zK-GrAnkHRsHxKOaDONpM");
        //
        String openidStr = openid.toString();
        sm.put("openid", openidStr);
        getLogger().debug("opendid:" + openid);
        String sign = WeiXinUtil.createSign(sm);
        getLogger().debug("sign:" + sign);
        String xml = XmlUtil.createXml(sm, sign);
        getLogger().debug("post:" + xml);
        String result = HttpClientUtil.postXML(url, xml);
        getLogger().debug("result:" + result);
        Map<String, String> xmlmap = XmlUtil.parseXml(result);
        // 返回预支付标识
        String prepay_id = xmlmap.get("prepay_id");
        // 凡是拿不到prepay_id都统统归结为下单失败
        if (StringUtils.isEmpty(prepay_id)) {
            throw new ServiceException("微信下单失败");
        }
        return "prepay_id=" + prepay_id;
    }

我是通过授权跳转的方式获取openid,即在点击“去支付”按钮的时候跳转到微信平台进行自动授权然后跳转会指定页面,也可在系统登录的时候就进行授权跳转。贴代码注意加粗代码即可。还是推荐看文档 授权跳转 页面跳转授权

<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${payUrl2}&response_type=code&state=${user.uid}&scope=snsapi_base" class="paymentbtn">

redirect_uri为你要授权之后跳转回来的url

    /**
     * 
     * 活动报名
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public String payApply() {
        Map<String, Object> user = (Map<String, Object>) WebUtils.getSessionAttribute("user");
**        // 获得微信支付返回来的state,用来存储登录用户的uid这个时候重新从接口中
        String state = WebUtils.getParameter("state");**
        getLogger().info("获取授权之后的state" + state);
        if (user == null && StringUtils.isNotEmpty(state)) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("uid", state);
            String userStr = HttpClientUtil.doGet("http://120.24.240.104/bikeapi/?m=user&a=get_user", map);
            user = (Map<String, Object>) JSON.parse(userStr);
            ActionContext.getContext().getSession().put("user", user);
        }

        if (getActivityId() == null) {
            return "activityerror";
        }
        Activity av = activityService.findById(getActivityId());
        setActivity(av);
**        // 获得用户的openid,支付的时候需要用到
        String code = WebUtils.getParameter("code");**
        // String code = "021ed6c6c2f9b4689e166d7d0ea9caaD";
        if (StringUtils.isEmpty(code)) {
            // 不能获得支付授权
            setMsg("获得微信支付授权失败,不能使用微信支付");
        } else {
**            // ------------一下为获取openid的代码
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token";
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("appid", WeiXinUtil.APPID);
            map.put("secret", WeiXinUtil.APPSECRET);
            map.put("code", code);
            map.put("grant_type", "authorization_code");
            try {
                // 授权字符串
                String authStr = HttpClientUtil.doPost(url, map);
                JSONObject json = new JSONObject(authStr);
                String openid = json.getString("openid");
                // 把他set到session中,这应该是最简单的了吧
                WebUtils.getSession().setAttribute("openid", openid);**
            } catch (Exception e) {
                e.printStackTrace();
                setMsg("获得微信支付授权失败,不能使用微信支付");
            }
        }
        // 没有登录不能报名
        if (user != null) {
            // 查询当前用户的余额,如果查不到那么就是0元咯
            BigDecimal balance = userService.findBalanceByUid(Long.valueOf(user.get("uid").toString()));
            this.setUserBalance(balance);
            return "payapply";
        } else {
            fromUrl = "/index/index!login.action?from_url=/activity/activity!apply.action?id="
                    + String.valueOf(getActivityId());
            return "login";
        }
    }

好的,完成了统一下单之后你应该获取到一个package格式为prepay_id=123456789这样子的订单信息,那么接下来就可以在页面发起支付请求了。 刚开始的时候我按照文档的发起H5支付,结果怎么调试都不成功,相信很多朋友也是在这个地方遇到问题 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7 这个应该是官方文档没更新的原因,新版的微信中已经支持这种发起支付调用,而应该采用JSSDK发起支付请求。直接看到支付的api 输入链接说明 输入图片说明 遇到不懂的地方或者缺少的参数请往上看文档。 主要具体步骤有 输入图片说明

最后贴一下我的发起支付的页面代码,我只能帮你们到这里了,剩下的就是调试了。

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/common/header.jsp" %>
<title>微信支付</title>
<link rel="stylesheet" type="text/css" href="css/activity.css">
<script type="text/javascript" charset="UTF-8" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">

function pay(){
    var appId = $('#appId').val();
    var timeStamp = $('#timeStamp').val();
    var nonceStr = $('#nonceStr').val();
    var pk = $('#package').val();
    var signType = $('#signType').val();
    var paySign = $('#paySign').val();
    //config
    var timeStamp2 = $('#timeStamp2').val();
    var nonceStr2 = $('#nonceStr2').val();
    var signature = $('#signature').val();
    //
    var activityId = $('#activityId').val();

    wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: appId, // 必填,公众号的唯一标识
        timestamp:timeStamp2 , // 必填,生成签名的时间戳
        nonceStr: nonceStr2, // 必填,生成签名的随机串
        signature: signature,// 必填,签名,见附录1
        jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
    });
    wx.ready(function(){
        // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
        wx.chooseWXPay({
            timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
            nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
            package: pk, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
            signType: signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
            paySign: paySign, // 支付签名
            complete: function (res) {
                // 支付成功后的回调函数
                location.href=basePath+'/activityorder/activity-order!list.action?activityId='+activityId;
            }
        });
    });
}
</script>
</head>
<body onload="pay()">
    <input id="activityId" type="hidden" value="${activityId}" />

    <input id="appId" type="hidden" value="${payparam.appId}" />
    <input id="timeStamp" type="hidden" value="${payparam.timeStamp}" />
    <input id="nonceStr" type="hidden" value="${payparam.nonceStr}" />
    <input id="package" type="hidden" value="${payparam.package1}" />
    <input id="signType" type="hidden" value="${payparam.signType}" />
    <input id="paySign" type="hidden" value="${payparam.paySign}" />

    <input id="timeStamp2" type="hidden" value="${apijsmap.timestamp}" />
    <input id="nonceStr2" type="hidden" value="${apijsmap.noncestr}" />
    <input id="signature" type="hidden" value="${apijsmap.signature}" />
</body>
</html>

最后记得在公众平台的公众权限配置,你发起支付的页面一定要是在公众平台设置了授权的页面,调用jsjdk的页面也要授权了的。至于具体要哪些授权,地方太多了慢慢找吧。