我正在尝试编写一个MVC3应用程序,该应用程序动态构建一个vCard(.vcf)文件,供移动设备上的人员扫描QR码时下载。我找到了一个示例here来构建和返回vCards。经过一些操作后,我能够在桌面计算机上运行它,但每次我尝试在移动设备上下载文件时,下载都会失败。我原以为它发送的标题有问题,所以我做了一些挖掘,发现了一些关于android here的HTTP标题的有用信息。不幸的是,甚至调整标题并没有改变任何东西。
第一部分是控制器,稍后将采用URL参数。保持测试简单。
public class APIController : Controller
{
public vCardResult vCard()
{
vCard card = new vCard
{
FirstName = "First",
LastName = "Last",
StreetAddress = "70 Street Adr.",
City = "Atlanta",
State = "GA",
CountryName = "United States",
Mobile = "5558675309",
Organization = "MyCompany",
HomePage = "www.Google.com",
JobTitle = "Software Developer",
Zip = "30318",
Email = "FirstLast@MyCompany.com",
};
return new vCardResult(card);
}
这是vCard模型
public class vCard
{
//I cut out the properties to save space
public override string ToString()
{
var builder = new StringBuilder();
builder.AppendLine("BEGIN:VCARD");
builder.AppendLine("VERSION:2.1");
builder.AppendLine("FN:" + FirstName + " " + LastName);
builder.AppendLine("N:" + LastName + ";" + FirstName);
builder.AppendLine("TEL;CELL:" + Mobile);
builder.AppendLine("TEL:");
builder.AppendLine("EMAIL;INTERNET:" + Email);
builder.AppendLine("TEL;FAX:");
builder.AppendLine("TITLE:" + JobTitle);
builder.AppendLine("ORG:" + Organization);
builder.AppendLine("ADR:;;" + StreetAddress + ";" + City + ";" + ";" + Zip + ";");
builder.AppendLine("REV:20120730T15034z");
builder.AppendLine("END:VCARD");
return builder.ToString();
}
}
最后是行动结果
public class vCardResult : ActionResult
{
private vCard _card;
protected vCardResult() { }
public vCardResult(vCard card)
{
_card = card;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.ContentType = "text/vcard";
response.AddHeader("Content-Disposition", "attachment; fileName=\"" + _card.FirstName + "_" + _card.LastName + ".VCF\"");
var cardString = _card.ToString();
var inputEncoding = Encoding.Default;
var outputEncoding = Encoding.GetEncoding("windows-1257");
var cardBytes = inputEncoding.GetBytes(cardString);
var outputBytes = Encoding.Convert(inputEncoding,
outputEncoding, cardBytes);
response.OutputStream.Write(outputBytes, 0, outputBytes.Length);
}
}
与我之前列出的例子没有太大的不同,但我想在我走得更远之前至少得到这个功能。
我检查了服务器发送的响应与类似工作系统的响应(我无法访问源代码),我没有看到很多差异所以我不确定为什么他们的vCard打开手机的联系人列表添加为新联系人,我的下载失败。答复如下。
示例响应(工作):
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Disposition: attachment; filename=5240000053568089.vcf
Content-Type: text/x-vcard
Transfer-Encoding: chunked
Date: Tue, 31 Jul 2012 21:18:31 GMT
110
BEGIN:VCARD
VERSION:2.1
FN:First Last
N:Last;First
TEL;CELL:5558675309
TEL:
EMAIL;INTERNET:FirstLast@MyCompany.com
TEL;FAX:
TITLE:Software Developer
ORG:MyCompany
ADR:;;70 Street Adr.;Atlanta;GA;30318;
REV:20120523T150346Z
END:VCARD
0
我的应用
的回复HTTP/1.1 200 OK
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: text/vcard
Server: Microsoft-IIS/7.0
X-AspNetMvc-Version: 3.0
Content-Disposition: attachment; fileName=First_Last.vcf
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 31 Jul 2012 20:14:02 GMT
105
BEGIN:VCARD
VERSION:2.1
FN:First Last
N:Last;First
TEL;CELL:5558675309
TEL:
EMAIL;INTERNET:FirstLast@MyCompany.com
TEL;FAX:
TITLE:Software Developer
ORG:MyCompany
ADR:;;70 Street Adr.;Atlanta;GA;30346;
REV:20120730T15034z
END:VCARD
0
提前感谢您阅读本文以及您能提供的任何帮助/建议!
答案 0 :(得分:0)
你从未关闭过:
public class APIController : Controller
答案 1 :(得分:0)
但是网络配置的标准设置不允许使用点
为您添加一些补充资料
<&的System.Web GT;
< HttpHandlers的>
< add path =“ .less”verb =“GET”type =“dotless.Core.LessCssHttpHandler,dotless.Core”/>
< add path =“ .vcf”type =“System.Web.Handlers.TransferRequestHandler”verb =“GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS”/>
< / HttpHandlers的>
< /system.web>
< system.webServer>
< modules runAllManagedModulesForAllRequests =“true”/>
< validation validateIntegratedModeConfiguration =“false”/>
<处理>
< add name =“dotless”path =“ .less”verb =“GET”type =“dotless.Core.LessCssHttpHandler,dotless.Core”resourceType =“File”preCondition =“”/>
< add name =“ApiURIs-ISAPI-Integrated-4.0”path =“ .vcf”type =“System.Web.Handlers.TransferRequestHandler”verb =“GET,HEAD,POST,DEBUG,PUT,DELETE, PATCH,OPTIONS“preCondition =”integratedMode,runtimeVersionv4.0“/>
< /处理程序>
< /system.webServer>
这是通过Android浏览器下载vcard的一些棘手的方法,但它表达了更复杂的解决其他手机浏览器的下载联系人
答案 2 :(得分:0)
using Maavak.Models;
using Maavak.Models.Vcard;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Diagnostics;
using System.Text;
namespace Maavak.Controllers
{
//[Route("api/[controller]")]
public class VCardTestController : Controller
{
private readonly IHttpContextAccessor _httpContextAccessor;
public VCardTestController(
IHttpContextAccessor httpContextAccessor
)
{
_httpContextAccessor = httpContextAccessor;
_vcard = new Vcard
{
FirstName = "First",
LastName = "Last",
StreetAddress = "70 Street Adr.",
City = "Atlanta",
State = "GA",
CountryName = "United States",
Mobile = "5558675309",
Organization = "MyCompany",
HomePage = "www.Google.com",
JobTitle = "Software Developer",
Zip = "30318",
Email = "FirstLast@MyCompany.com",
};
}
private readonly Vcard _vcard;
[Route("vcardtest.vcf")]
public IActionResult Get()
{
try
{
const string text_x_vcard = "text/x-vcard";
HttpResponse response = _httpContextAccessor.HttpContext.Response;
_httpContextAccessor.HttpContext.Response.ContentType = "text/vcard";
_httpContextAccessor.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; fileName=\"" + _vcard.FirstName + "_" + _vcard.LastName + ".VCF\"");
string cardString = _vcard.ToString();
Encoding inputEncoding = Encoding.Default;
Encoding outputEncoding = Encoding.GetEncoding("windows-1255");
byte[] cardBytes = inputEncoding.GetBytes(cardString);
byte[] outputBytes = Encoding.Convert(inputEncoding,
outputEncoding, cardBytes);
return Content(cardString, text_x_vcard, Encoding.UTF8);
}
catch (Exception ex)
{
Debug.WriteLine($"[{ ClsGlobal.GetCurrentMethod() }] { ex.Message } : { ex.InnerException } - {ex.StackTrace}");
return NotFound();
}
}
}
}
这是课程
using System.Text;
namespace Maavak.Models.Vcard
{
public class Vcard
{
public string FirstName { get; set; }
public string CountryName { get; set; }
public string LastName { get; set; }
public string StreetAddress { get; set; }
public string Organization { get; set; }
public string Zip { get; set; }
public string State { get; set; }
public string City { get; set; }
public string Mobile { get; set; }
public string LandLine { get; set; }
public string Fax { get; set; }
public string HomePage { get; set; }
public string Email { get; set; }
public string JobTitle { get; set; }
public override string ToString()
{
var builder = new StringBuilder();
builder.AppendLine("BEGIN:VCARD");
builder.AppendLine("VERSION:2.1");
builder.AppendLine($"N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{ LastName };{ FirstName};;;;");
builder.AppendLine($"FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{ FirstName } { LastName }");
//builder.AppendLine("FN:" + FirstName + " " + LastName);
//builder.AppendLine("N:" + LastName + ";" + FirstName);
if (Mobile != null)
builder.AppendLine("TEL;CELL:" + Mobile);
if (LandLine != null)
builder.AppendLine("TEL;MOME:" + LandLine);
if (Email != null)
builder.AppendLine("EMAIL;INTERNET:" + Email);
if (Fax != null)
builder.AppendLine("TEL;FAX:");
if (JobTitle != null)
builder.AppendLine("TITLE:" + JobTitle);
if (Organization != null)
builder.AppendLine("ORG:" + Organization);
if (City != null)
builder.AppendLine("ADR:;;" + StreetAddress + ";" + City + ";" + ";" + Zip + ";");
//builder.AppendLine("REV:20120730T15034z");
builder.AppendLine("END:VCARD");
return builder.ToString();
}
}
}
工作演示here!
答案 3 :(得分:0)
using Maavak.Models;
using Maavak.Models.Vcard;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Diagnostics;
using System.Text;
namespace Maavak.Controllers
{
//[Route("api/[controller]")]
public class VCardController : Controller
{
private readonly IHttpContextAccessor _httpContextAccessor;
public VCardController(
IHttpContextAccessor httpContextAccessor
)
{
_httpContextAccessor = httpContextAccessor;
}
[Route("{FirstName}-{LastName}-{Mobile}-{LandLine}-{Email}.vcf")]
public IActionResult Get(
string firstName,
string lastName,
string mobile,
string landLine,
string email
)
{
try
{
Vcard _vcard = new Vcard()
{
FirstName = firstName,
LastName = lastName,
Mobile = mobile,
LandLine = landLine,
Email = email
};
const string text_x_vcard = "text/x-vcard";
HttpResponse response = _httpContextAccessor.HttpContext.Response;
_httpContextAccessor.HttpContext.Response.ContentType = "text/vcard";
_httpContextAccessor.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; fileName=\"" + _vcard.FirstName + " " + _vcard.LastName + ".VCF\"");
return Content(_vcard.ToString(), text_x_vcard, Encoding.UTF8);
}
catch (Exception ex)
{
Debug.WriteLine($"[{ ClsGlobal.GetCurrentMethod() }] { ex.Message } : { ex.InnerException } - {ex.StackTrace}");
return NotFound();
}
}
}
}
然后像使用它
https://maavak.taboil.com/first-last-55555-66666-first@last.com.vcf
答案 4 :(得分:0)
此解决方案适用于希伯来字符
using Maavak.Models;
using Maavak.Models.Vcard;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Diagnostics;
using System.Net;
using System.Text;
namespace Maavak.Controllers
{
//[Route("api/[controller]")]
public class VCardController : Controller
{
private readonly IHttpContextAccessor _httpContextAccessor;
public VCardController(
IHttpContextAccessor httpContextAccessor
)
{
_httpContextAccessor = httpContextAccessor;
}
[Route("{FirstName}-{LastName}-{Mobile}-{LandLine}-{Email}.vcf")]
public IActionResult Get(
string firstName,
string lastName,
string mobile,
string landLine,
string email
)
{
const string text_x_vcard = "text/x-vcard";
try
{
Vcard _vcard = new Vcard()
{
FirstName = firstName,
LastName = lastName,
Mobile = mobile,
LandLine = landLine,
Email = email
};
_httpContextAccessor.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; fileName=\"" +
CleanNonAsciiForVcardHeadr(_vcard.FirstName) + " " +
CleanNonAsciiForVcardHeadr(_vcard.LastName) + ".VCF\"");
return Content(_vcard.ToString(), text_x_vcard, Encoding.UTF8);
}
catch (Exception ex)
{
Debug.WriteLine($"[{ ClsGlobal.GetCurrentMethod() }] { ex.Message } : { ex.InnerException } - {ex.StackTrace}");
return NotFound();
}
}
private string CleanNonAsciiForVcardHeadr(string str)
{
return WebUtility.UrlEncode(str).Replace("+", "%20");
}
}
}
班是这个
using System.Net;
using System.Text;
namespace Maavak.Models.Vcard
{
public class Vcard
{
public string FirstName { get; set; }
public string CountryName { get; set; }
public string LastName { get; set; }
public string StreetAddress { get; set; }
public string Organization { get; set; }
public string Zip { get; set; }
public string State { get; set; }
public string City { get; set; }
public string Mobile { get; set; }
public string LandLine { get; set; }
public string Fax { get; set; }
public string HomePage { get; set; }
public string Email { get; set; }
public string JobTitle { get; set; }
public override string ToString()
{
var builder = new StringBuilder();
string n = $"{ CleanNonAsciiForVcard(LastName) };{ CleanNonAsciiForVcard(FirstName) };;;";
string fn = $"{ CleanNonAsciiForVcard(FirstName) } { CleanNonAsciiForVcard(LastName) }";
builder.AppendLine("BEGIN:VCARD");
builder.AppendLine("VERSION:2.1");
builder.AppendLine($"N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{ n }");
builder.AppendLine($"FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{ fn }");
//builder.AppendLine("FN:" + FirstName + " " + LastName);
//builder.AppendLine("N:" + LastName + ";" + FirstName);
if (Mobile != null)
builder.AppendLine("TEL;CELL:" + Mobile);
if (LandLine != null)
builder.AppendLine("TEL;HOME:" + LandLine);
if (Email != null)
builder.AppendLine("EMAIL;INTERNET:" + Email);
if (Fax != null)
builder.AppendLine("TEL;FAX:");
if (JobTitle != null)
builder.AppendLine("TITLE:" + JobTitle);
if (Organization != null)
builder.AppendLine("ORG:" + Organization);
if (City != null)
builder.AppendLine("ADR:;;" + StreetAddress + ";" + City + ";" + ";" + Zip + ";");
//builder.AppendLine("REV:20120730T15034z");
builder.AppendLine("END:VCARD");
return builder.ToString();
}
private string CleanNonAsciiForVcard(string str)
{
return WebUtility.UrlEncode(str).Replace("+", "=20").Replace("%", "=");
}
}
}
像这样使用它
https://maavak.taboil.com/first-last-55555-66666-first@last.com.vcf
或
https://maavak.taboil.com/first-last-55555-%20-%20.vcf
https://maavak.taboil.com/עברית-עברית%20משפחה-55555-%20-%20.vcf