iPadからPDFデータをサーバに送信し、サーバ側はジェネリックハンドラで受信する（Swift2.2, XCode7.3.1 / VB.NET, ashx, VS2008）

[WKWebViewにHTML表示させ、PDF化する（Swift2.2, XCode7.3.1）](http://qiita.com/keita1987/items/c3053bb978c1d5b2b3d3)のつづき

#したいこと
iPad側でPDF作成して、Windowsサーバに送信する。
サーバ側はジェネリックハンドラ(ashx)で受信して、PDFを保存する。

サーバ側の処理をPHPで行えば、とても簡単にできました。
[PHPの場合の参考URL](https://sites.google.com/a/gclue.jp/swift-docs/ni-yinki100-ios/13-http/fairuwoappurodosuru)
PHPがNGでジェネリックハンドラで処理しなければいけなかったので、苦労したのでメモしておきます。


#コード
```swift:ViewController.swift
import UIKit
import WebKit

extension NSMutableData {
    func appendString(string: String) {
        let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
        appendData(data!)
    }
}

class ViewController: UIViewController, WKNavigationDelegate, UIScrollViewDelegate {
    private var subView: UIView!
    private var webView: WKWebView!
    
    override func viewDidLoad()
    {
        super.viewDidLoad()

        let size = view.frame.size
        subView = UIView(frame: CGRectMake(0, 0, size.width, size.height - 50))
        
        let btn = UIButton(type: .System)
        btn.frame = CGRectMake(0, size.height - 50, 90, 40)
        btn.setTitle("set HTML", forState: .Normal)
        btn.addTarget(self, action: #selector(ViewController.tapBtn(_:)), forControlEvents: .TouchUpInside)
        
        let btn2 = UIButton(type: .System)
        btn2.frame = CGRectMake(size.width * 0.35, size.height - 50, 90, 40)
        btn2.setTitle("set from web", forState: .Normal)
        btn2.addTarget(self, action: #selector(ViewController.tapBtn2(_:)), forControlEvents: .TouchUpInside)
        
        let btn3 = UIButton(type: .System)
        btn3.frame = CGRectMake(size.width * 0.7, size.height - 50, 90, 40)
        btn3.setTitle("create pdf", forState: .Normal)
        btn3.addTarget(self, action: #selector(ViewController.tapBtn3(_:)), forControlEvents: .TouchUpInside)
        
        view.addSubview(subView)
        view.addSubview(btn)
        view.addSubview(btn2)
        view.addSubview(btn3)
        
        webView = WKWebView()
        setupSubViews(subView)
    }

    internal func tapBtn(sender: UIButton) {
//        webView.loadHTMLString(getStrFromFile("test.html"), baseURL: nil)
        webView.loadHTMLString("hoge<br>piyo<br>foo<br>bar<br>hogeeeeeeeeeeeeeeeee", baseURL: nil)
    }
    
    internal func tapBtn2(sender: UIButton) {
        let req = NSURLRequest(URL: NSURL(string:"http://www.yahoo.co.jp/")!)
        webView.loadRequest(req)
    }
    
    internal func tapBtn3(sender: UIButton) {
//        let path = NSHomeDirectory().stringByAppendingString("/hoge.pdf")
//        PDFMaker.make([webView], path: path)
        
        // PDFファイルは作成せずにNSData化する
        let data = PDFMaker.make([webView])
        //        data.writeToURL(NSURL(fileURLWithPath: path), atomically: true)
        uploadPDF(data)
    }
    
    
    private func setupSubViews(v: UIView)
    {
//        webView.navigationDelegate = self
//        webView.scrollView.delegate = self
        webView.translatesAutoresizingMaskIntoConstraints = false
        v.addSubview(webView)
        var viewBindingsDict = [String: AnyObject]()
        viewBindingsDict["webView"] = webView
        v.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewBindingsDict))
        v.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewBindingsDict))
    }
    
    private func uploadPDF(pdfData: NSData) -> Bool {
        var ret = true
        
        let request = NSMutableURLRequest(URL: NSURL(string: "ashxファイルのURL")!)
        request.HTTPMethod = "POST"
        let param = [
            "userId" : "12345"
        ]
        let boundary = generateBoundaryString()
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", dataKey: pdfData, boundary: boundary)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in
            if error != nil {
                print("error=\(error)")
                ret = false
            }
            print("******* response = \(response)")
            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("****** response data = \(responseString!)")
            dispatch_async(dispatch_get_main_queue(),{
            });
        }
        task.resume()
        
        return ret
    }
    
    private func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, dataKey: NSData, boundary: String) -> NSData {
        let body = NSMutableData()
        if parameters != nil {
            for (key, value) in parameters! {
                body.appendString("--\(boundary)\r\n")
                body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
                body.appendString("\(value)\r\n")
            }
        }
        //        let filename = "user-profile.jpg"
        let filename = "1234567890.pdf"
        //        let mimetype = "image/jpg"
        let mimetype = "application/pdf"
        body.appendString("--\(boundary)\r\n")
        body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.appendData(dataKey)
        body.appendString("\r\n")
        body.appendString("--\(boundary)--\r\n")
        return body
    }
    
    private func generateBoundaryString() -> String {
        return "Boundary-\(NSUUID().UUIDString)"
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // プロジェクトに追加したローカルファイルの文字列取得
    private func getStrFromFile(fname: String) -> String {
        var ret = ""
        var path = NSString(string: fname)
        // Encode 日本語ファイル対応
        path = path.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
        let ext = path.pathExtension
        let filename = path.stringByDeletingPathExtension
        do {
            if let path = NSBundle.mainBundle().pathForResource(filename, ofType: ext) {
                ret = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)
            }
        } catch {
            print("error getStrFromFile")
        }
        return ret
    }
}

// PDF作成クラス
class PDFMaker {
    private class func renderViews(views: [UIView]) {
        guard let context = UIGraphicsGetCurrentContext() else {
            return
        }
        views.forEach {
            if let scrollView = $0 as? UIScrollView {
                let tmpInfo = (offset: scrollView.contentOffset, frame: scrollView.frame)
                scrollView.contentOffset = CGPointZero
                scrollView.frame = CGRect(origin: CGPointZero, size: scrollView.contentSize)
                UIGraphicsBeginPDFPageWithInfo(scrollView.frame, nil)
                $0.layer.renderInContext(context)
                scrollView.frame = tmpInfo.frame
                scrollView.contentOffset = tmpInfo.offset
            } else {
                UIGraphicsBeginPDFPageWithInfo($0.bounds, nil)
                $0.layer.renderInContext(context)
            }
        }
    }
    
    class func make(views: [UIView], path: String) {
        UIGraphicsBeginPDFContextToFile(path, CGRectZero, nil)
        renderViews(views)
        UIGraphicsEndPDFContext()
    }
    
    class func make(views: [UIView]) -> NSData {
        let data = NSMutableData()
        UIGraphicsBeginPDFContextToData(data, CGRectZero, nil)
        renderViews(views)
        UIGraphicsEndPDFContext()
        return data
    }
}
```

```vbnet:サーバ側.ashx.vb
Imports System.Web
Imports System.Web.Services
Imports System.IO

Public Class emsapp
    Implements System.Web.IHttpHandler

    Private resp As HttpResponse = Nothing
    Private context As HttpContext = Nothing
    Private dirPath As String = System.Configuration.ConfigurationManager.AppSettings("dirPath")

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        resp = context.Response
        Me.context = context
        context.Response.ContentType = "text/plain"


        If Not IO.Directory.Exists(dirPath) Then
            IO.Directory.CreateDirectory(dirPath)
        End If

        Dim files = context.Request.Files
        For i As Integer = 0 To files.Count - 1
            Dim file = files(i)
            Dim fnameTmp = context.Server.MapPath("~/" + file.FileName)
            file.SaveAs(fnameTmp)
            Dim fname = IO.Path.Combine(dirPath, file.FileName)

            If IO.File.Exists(fname) Then
                IO.File.Delete(fname)
            End If
            IO.File.Move(fnameTmp, fname)
            println(fname)
        Next

        '' PDFはできるが真っ白・・・
        'Dim str = New StreamReader(context.Request.InputStream, context.Request.ContentEncoding).ReadToEnd()
        ''Dim sr As New System.IO.StreamReader(context.Request.InputStream)
        ''Dim str = New StreamReader(context.Request.InputStream).ReadToEnd
        'Dim path = IO.Path.Combine(dirPath, "hoge.pdf")
        ''Dim sw = New StreamWriter(path, True, System.Text.Encoding.ASCII)
        'Dim sw = New StreamWriter(path, True, System.Text.Encoding.Default)
        'sw.Write(str)
        'sw.Close()
    End Sub

    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

    Private Sub print(ByVal s As String)
        resp.Write(s)
    End Sub

    Private Sub println(ByVal s As String)
        resp.Write(s + vbCrLf)
    End Sub

End Class
```