I'm uploading excel file from android to C# the request from android is arriving to c# server(I don't want to use asp.net).
I've built from scratch a simple HTTPServe, I do't how to handle multipart data upload in c# that's my code :
Request.cs:
class Request
{
public String type { get; set; }
public String url { get; set; }
public String host { get; set; }
private Request(String type,String url,String host)
{
this.type = type;
this.url = url;
this.host = host;
}
public static Request GetRequest(String request)
{
if (String.IsNullOrEmpty(request))
return null;
String[] tokens = request.Split(' ');
String type = tokens[0];
String url = tokens[1];
String host = tokens[4];
return new Request(type, url, host);
}
}
Response.cs:
class Response
{
private Byte[] data = null;
private String status;
private String mime;
private Response(String status,String mime,Byte[] data)
{
this.status = status;
this.data = data;
this.mime = mime;
}
public static Response From(Request request)
{
Console.WriteLine(request.type);
if (request == null)
return MakeNullRequest();
if (request.type.Equals("POST"))
{
return UploadCompleteResponse(request);
}
return MakeFromExcel();
}
private static Response UploadCompleteResponse(Request request)
{ //Handling the multipart request here but I don't know how that is a simple example
Console.WriteLine("uploaded!!");
byte[] bytes = Encoding.ASCII.GetBytes("uploaded!!");
return new Response("ok 200","text/plain",bytes);
}
//private static Response MakeFromFile(FileInfo f)
//{
// // to do later
// //return new Response("200 ok", "text/html", d);
//}
//Retruning an excel file response
private static Response MakeFromExcel()
{
String file = Environment.CurrentDirectory + HTTPServer.EXCEL_DIR+"brains.xlsx";
Console.WriteLine(file);
FileInfo info = new FileInfo(file);
if (info.Exists)
{
FileStream fs = info.OpenRead();
BinaryReader read = new BinaryReader(fs);
Byte[] d = new Byte[fs.Length];
read.Read(d, 0, d.Length);
fs.Close();
return new Response("200 ok", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", d);
}
return PageNotFound();
}
private static Response MakeNullRequest()
{
String file = Environment.CurrentDirectory+HTTPServer.MSG_DIR +"400.html";
Console.WriteLine(file);
FileInfo info = new FileInfo(file);
FileStream fs=info.OpenRead();
BinaryReader read=new BinaryReader(fs);
Byte[] d = new Byte[fs.Length];
read.Read(d, 0, d.Length);
fs.Close();
return new Response("400 Bad Request", "text/html", d);
}
private static Response PageNotFound()
{
String file = Environment.CurrentDirectory + HTTPServer.MSG_DIR + "400.html";
FileInfo info = new FileInfo(file);
FileStream fs = info.OpenRead();
BinaryReader read = new BinaryReader(fs);
Byte[] d = new Byte[fs.Length];
read.Read(d, 0, d.Length);
return new Response("404 Not Found", "text/html", d);
}
public void Post(NetworkStream stream)
{
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine(String.Format("{0} {1}\r\nServer: {2}\r\nContent-Type: {3}\r\nAccept-Ranges: 255 bytes\r\nContent-Length: {4}\r\n", HTTPServer.VERSION
, status, HTTPServer.NAME, mime, data.Length));
writer.Flush();
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
}
}
In the above code I used more than one type of response You can access and the request fields by increasing the size of the token array.
HTTServer.cs:
class HTTPServer
{
public const String MSG_DIR = "\\root\\msg\\";
public const String EXCEL_DIR = "\\root\\excel\\";
public const String WEB_DIR = "\\root\\web\\";
public const String VERSION = "HTTP/1.1";
public const String NAME = "Thecode007 HTTP SERVER v 1.0";
private bool running = false;
private TcpListener listener;
public HTTPServer(int port)
{
listener = new TcpListener(IPAddress.Any,port);
}
public void Start() {
Thread serverThread = new Thread(new ThreadStart(Run));
serverThread.Start();
}
private void Run()
{
running = true;
listener.Start();
while (running)
{
Console.WriteLine("Waiting for connection...");
TcpClient client = listener.AcceptTcpClient();
HandleClient(client);
Console.WriteLine("Client connected!");
}
running = false;
listener.Stop();
}
private void HandleClient(TcpClient client)
{
StreamReader reader = new StreamReader(client.GetStream());
String msg = "";
while (reader.Peek() != -1)
{
msg += reader.ReadLine()+"\n";
}
Console.WriteLine(msg);
Request req = Request.GetRequest(msg);
Response resp = Response.From(req);
resp.Post(client.GetStream());
}
}
And here is the main method:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Serving on port 9000");
HTTPServer server = new HTTPServer(9000);
server.Start();
Console.ReadLine();
}
}
Disclaimer: You should never write a HTTP server directly with TcpClient for any production work. There are far too many specifications to be accounted for and C# has these built in to any Asp.Net web server you use.
That being said, for an exercise this is a matter of parsing the request in a specific way. You should be able to reference these questions to learn more about the details of multipart boundary:
What is http multipart request?
What should a Multipart HTTP request with multiple files look like?
Essentially, you will have to read a header from the http headers (Content-Type), and parse the value of boundary= to determine what is separating the key/value pairs of the multipart form in the request body. Once you've got the boundary you will have to parse the body of the request into the real key/value pairs of the form. From there, the contents of the uploaded file will be the value of whatever key the form submits it as.
Read more on the official W3 spec
Response.cs:
class Response
{
private Byte[] data = null;
private String status;
private String mime;
private Response(String status,String mime,Byte[] data)
{
this.status = status;
this.data = data;
this.mime = mime;
}
public static Response From(Request request)
{
if (request == null)
return MakeNullRequest();
if (request.type.Equals("POST"))
{
return UploadCompleteResponse(request);
}
return MakeFromExcel();
}
private static Response UploadCompleteResponse(Request request)
{ //I added on the rquest array the datapart which contains data
String data=request.data;
byte[] bytes = Encoding.ASCII.GetBytes("uploaded!!");
return new Response("ok 200","text/plain",bytes);
}
//private static Response MakeFromFile(FileInfo f)
//{
// // to do later
// //return new Response("200 ok", "text/html", d);
//}
//Retruning an excel file response
private static Response MakeFromExcel()
{
String file = Environment.CurrentDirectory + HTTPServer.EXCEL_DIR+"brains.xlsx";
Console.WriteLine(file);
FileInfo info = new FileInfo(file);
if (info.Exists)
{
FileStream fs = info.OpenRead();
BinaryReader read = new BinaryReader(fs);
Byte[] d = new Byte[fs.Length];
read.Read(d, 0, d.Length);
fs.Close();
return new Response("200 ok", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", d);
}
return PageNotFound();
}
private static Response MakeNullRequest()
{
String file = Environment.CurrentDirectory+HTTPServer.MSG_DIR +"400.html";
Console.WriteLine(file);
FileInfo info = new FileInfo(file);
FileStream fs=info.OpenRead();
BinaryReader read=new BinaryReader(fs);
Byte[] d = new Byte[fs.Length];
read.Read(d, 0, d.Length);
fs.Close();
return new Response("400 Bad Request", "text/html", d);
}
private static Response PageNotFound()
{
String file = Environment.CurrentDirectory + HTTPServer.MSG_DIR + "400.html";
FileInfo info = new FileInfo(file);
FileStream fs = info.OpenRead();
BinaryReader read = new BinaryReader(fs);
Byte[] d = new Byte[fs.Length];
read.Read(d, 0, d.Length);
return new Response("404 Not Found", "text/html", d);
}
public void Post(NetworkStream stream)
{
try
{
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine(String.Format("{0} {1}\r\nServer: {2}\r\nContent-Type: {3}\r\nAccept-Ranges: 255 bytes\r\nContent-Length: {4}\r\n", HTTPServer.VERSION
, status, HTTPServer.NAME, mime, data.Length));
writer.Flush();
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
}catch(Exception ex){
}
}
}
Request.cs:
class Request
{
public String type { get; set; }
public String url { get; set; }
public String host { get; set; }
public String data { get; set; }
private Request(String type,String url,String host)
{
this.type = type;
this.url = url;
this.host = host;
}
private Request(String type, String url, String host,String data)
{
this.type = type;
this.url = url;
this.host = host;
this.data = data;
}
public static Request GetRequest(String request)
{
if (String.IsNullOrEmpty(request))
return null;
String[] tokens = request.Split(' ');
String type = tokens[0];
String url = tokens[1];
String host = tokens[4];
String data = "N/A";
if (tokens.Length >= 9)
{
data = tokens[8];
}
return new Request(type, url, host, data);
}
}
Secondly my android client was excpecting a response which is responsbody type not a plain text thats why the data was never sent....
Related
I am trying to open pdf in the cefsharp browser itself. But nothing is getting displayed when I open the pdf. I have set the logs to error level but there are no errors in it.
This is how I am registering the CefCustomScheme :
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CefSharpSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CefSharpSchemeHandlerFactory(),
IsCSPBypassing = true,
});
This is my CefSharpSchemeHandlerFactory :
public class CefSharpSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "local";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
if (schemeName == SchemeName && request.Url.EndsWith("CefSharp.Core.xml", System.StringComparison.OrdinalIgnoreCase))
{
//Convenient helper method to lookup the mimeType
var mimeType = ResourceHandler.GetMimeType(".xml");
//Load a resource handler for CefSharp.Core.xml
//mimeType is optional and will default to text/html
return ResourceHandler.FromFilePath("CefSharp.Core.xml", mimeType);
}
return new CefSharpSchemeHandler();
}
}
This is my CefSharpSchemeHandler :
internal class CefSharpSchemeHandler : IResourceHandler
{
private static readonly IDictionary<string, string> ResourceDictionary;
private string mimeType;
private MemoryStream stream;
static CefSharpSchemeHandler()
{
}
bool IResourceHandler.ProcessRequest(IRequest request, ICallback callback)
{
// The 'host' portion is entirely ignored by this scheme handler.
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
string resource;
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
Task.Run(() =>
{
using (callback)
{
var bytes = Encoding.UTF8.GetBytes(resource);
stream = new MemoryStream(bytes);
var fileExtension = Path.GetExtension(fileName);
mimeType = ResourceHandler.GetMimeType(fileExtension);
callback.Continue();
}
});
return true;
}
else
{
callback.Dispose();
}
return false;
}
void IResourceHandler.GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl)
{
responseLength = stream == null ? 0 : stream.Length;
redirectUrl = null;
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusText = "OK";
response.MimeType = mimeType;
}
bool IResourceHandler.ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
{
callback.Dispose();
if(stream == null)
{
bytesRead = 0;
return false;
}
//Data out represents an underlying buffer (typically 32kb in size).
var buffer = new byte[dataOut.Length];
bytesRead = stream.Read(buffer, 0, buffer.Length);
dataOut.Write(buffer, 0, buffer.Length);
return bytesRead > 0;
}
bool IResourceHandler.CanGetCookie(Cookie cookie)
{
return true;
}
bool IResourceHandler.CanSetCookie(Cookie cookie)
{
return true;
}
void IResourceHandler.Cancel()
{
}
void IDisposable.Dispose()
{
}
}
And this how I am opening My pdf file from some other class :
string pdfPath = #"D:\Magic\10774.pdf";
var mimeType = ResourceHandler.GetMimeType(".pdf");
ResourceHandler.FromFilePath(pdfPath, mimeType);
I am not getting a hit at CefSharpSchemeHandlerFactory create method.
Using c# with the .net framework and microsoft azure and i am trying to upload a file in a cli which should be picked up by a webjob. I'm sure the webjob is fine but i am having problems getting upload to work.
// Pick URL location of service up from metadata
AudioSamples client = new AudioSamples(new AnonymousCredential());
var id = Console.ReadLine();
Console.WriteLine();
string path = "api/samples/" + id;
Console.WriteLine("Enter the file name.");
string fileName = Console.ReadLine();
using (var stream = File.OpenRead(fileName))
{
HttpOperationResponse response = await client.PutAsync(path, new StreamContent(stream));
}
From what i understand the PutAsync should work for streaming the file but it gives me an error saying the command doesn't exist
this api should also be used with the upload to a blob but im not sure how it connect it to the client.
namespace AudioSamples.Controllers
{
[ApiExplorerSettings(IgnoreApi = true)]
public class DataController : ApiController
{
private const String partitionName = "AudioSamples_Partition_1";
private CloudStorageAccount storageAccount;
private CloudTableClient tableClient;
private CloudTable table;
private BlobStorageService _blobStorageService = new BlobStorageService();
private CloudQueueService _queueStorageService = new CloudQueueService();
String name;
public DataController()
{
storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureWebJobsStorage"].ToString());
tableClient = storageAccount.CreateCloudTableClient();
table = tableClient.GetTableReference("AudioSamples");
}
private void deleteOldBlobs(AudioSampleEntityModel sample)
{
CloudBlobContainer blobContainer = _blobStorageService.getCloudBlobContainer();
CloudBlockBlob blob;
if (sample.Blob != null)
{
blob = blobContainer.GetBlockBlobReference(sample.Blob);
blob.Delete();
}
if (sample.SampleBlob != null)
{
blob = blobContainer.GetBlockBlobReference(sample.SampleBlob);
blob.Delete();
}
}
// PUT: api/Data/5
public IHttpActionResult Put(String id)
{
// PUT – see also ProductsController.cs from Lab 4
// Create a retrieve operation.
// id is a parameter of method and forms the row key
TableOperation retrieveOperation =
TableOperation.Retrieve<AudioSampleEntityModel>(partitionName, id);
TableResult getOperationResult = table.Execute(retrieveOperation);
if (getOperationResult.Result == null)
return NotFound();
AudioSampleEntityModel sample = (AudioSampleEntityModel)getOperationResult.Result;
deleteOldBlobs(sample);
try
{
CloudBlobContainer blobContainer = _blobStorageService.getCloudBlobContainer();
name = string.Format("{0}{1}", Guid.NewGuid(), ".mp3");
String path = "/mp3s" + name;
var baseUrl = Request.RequestUri.GetLeftPart(UriPartial.Authority);
String sampleURL = baseUrl.ToString() + "/api/data/" + id;
sample.SampleBlobURL = sampleURL;
sample.Blob = path;
sample.CreatedDate = DateTime.Now;
sample.SampleDate = null;
var updateOperation = TableOperation.InsertOrReplace(sample);
table.Execute(updateOperation);
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(sample.Blob);
var request = HttpContext.Current.Request;
blob.Properties.ContentType = "audio/mpeg3";
blob.UploadFromStream(request.InputStream);
}
catch (Exception e)
{
System.Diagnostics.Trace.WriteLine("DataController(PUT): " + e.Message);
return BadRequest("DataController(PUT): " + e.Message);
}
try
{
CloudQueue sampleQueue = _queueStorageService.getCloudQueue();
var queueMessageSample = new AudioSampleEntityModel(partitionName, id);
sampleQueue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(queueMessageSample)));
}
catch (Exception e)
{
System.Diagnostics.Trace.WriteLine("DataController(PUT): " + e.Message);
return BadRequest("DataController(PUT): " + e.Message);
}
System.Diagnostics.Trace.WriteLine(String.Format("*** WebRole: Enqueued '{0}'", sample.Blob));
return StatusCode(HttpStatusCode.NoContent);
}
}
}
This is the webjob which i think is working fine.
public class Functions
{
public static void GenerateSample(
[QueueTrigger("audiosamplemaker")] AudioSampleEntityModel sampleInQueue,
[Table("Samples", "{PartitionKey}", "{RowKey}")] AudioSampleEntityModel sampleInTable,
[Blob("audiocollection/audio/{queueTrigger}")] CloudBlockBlob inputBlob,
[Blob("audiocollection/samples/{queueTrigger}")] CloudBlockBlob outputBlob, TextWriter logger,
[Table("Samples")] CloudTable tableBinding, TextWriter kek)
{
//use log.WriteLine() rather than Console.WriteLine() for trace output
logger.WriteLine("GenerateSample() started...");
logger.WriteLine("Input blob is: " + sampleInQueue);
// Open streams to blobs for reading and writing as appropriate.
// Pass references to application specific methods
using (Stream input = inputBlob.OpenRead())
using (Stream output = outputBlob.OpenWrite())
{
createSample(input, output, 20);
outputBlob.Properties.ContentType = "audio/mp3";
outputBlob.Metadata["Title"] = inputBlob.Metadata["Title"];
}
logger.WriteLine("GenerateSample() completed...");
}
private static void createSample(Stream input, Stream output, int duration)
{
using (var reader = new Mp3FileReader(input, wave => new NLayer.NAudioSupport.Mp3FrameDecompressor(wave)))
{
Mp3Frame frame;
frame = reader.ReadNextFrame();
int frameTimeLength = (int)(frame.SampleCount / (double)frame.SampleRate * 1000.0);
int framesRequired = (int)(duration / (double)frameTimeLength * 1000.0);
int frameNumber = 0;
while ((frame = reader.ReadNextFrame()) != null)
{
frameNumber++;
if (frameNumber <= framesRequired)
{
output.Write(frame.RawData, 0, frame.RawData.Length);
}
else break;
}
}
}
}
In your web api controller, the put method only has one parameter named ‘id’. But in your client, you also passed a stream content in put method.
So you couldn’t call web api method successfully. And for this stream content, you could set a string or model type in Put method instead of file stream.
According to your description, I suppose you want to pass data from client to web api, then read data from this file path in web Api and upload data to a blob.
I have created a sample demo to upload a myfile.txt to a Blob. Other data types are similar to this. You could refer to.
Code in Console:
Code in AudioSampleEntityModel class:
public class AudioSampleEntityModel : TableEntity
{
public AudioSampleEntityModel()
{
}
public AudioSampleEntityModel(string partitionName, string id)
{
}
public string id { get; set; }
public string Blob { get; set; }
public string SampleBlob { get; set; }
public string SampleBlobURL { get; set; }
public DateTime CreatedDate { get; set; }
public string SampleDate { get; set; }
}
Code in Function.cs:
public class Functions
{
/// <summary>
/// pass the content from Queue to Blob(The content is from myfile.txt)
/// </summary>
/// <param name="model"></param>
/// <param name="orderBlob"></param>
public static void MultipleOutput(
[QueueTrigger("myqueue2")] AudioSampleEntityModel model,
[Blob("orders/myfile")] out string orderBlob) //create a container named 'orders'
{
orderBlob = model.SampleBlob; //store the content from SampleBlob property to Blob
}
}
Code in Program:
class Program
{
static void Main() {
Console.WriteLine("----------------Update Employee -------------------");
Console.WriteLine("Enter id which you want to update");
string id = Console.ReadLine();
var response=DemoData(id).Result;
Console.WriteLine("the data from webapi: "+response);
var host = new JobHost();
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
public static async Task<string> DemoData(string id)
{
HttpClient client = new HttpClient();
string path = "http://localhost:53581/api/values/" + id;
Console.WriteLine("Enter the file name.");
string fileName = Console.ReadLine();
string filepath = "E:\\JanleyZhang\\" + fileName;
var filepathJson = JsonConvert.SerializeObject(filepath);// convert other FileStream type to json string
var data = new StringContent(content: filepathJson,
encoding: Encoding.UTF8,
mediaType: "application/json");
var response = await client.PutAsync(path, data);//get response from web api
var content = response.Content;
var result = await content.ReadAsStringAsync();//read content from response
//upload the data to a queue
string connectionString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference("myqueue2");
queue.CreateIfNotExists();
AudioSampleEntityModel model = new AudioSampleEntityModel()
{
id=id,
SampleBlob=result //pass the result to this property
};
queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(model))); //store the file content to queue
return result;
}
}
Code in api controller:
public string Put(string id, [FromBody]string filepath) //pass two parameters
{
string b = "The id and model id are not equal.";
if (id == "1")
{
FileStream fs = File.OpenRead(filepath);
byte[] byt = new byte[fs.Length];
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(byt, 0, byt.Length) > 0)
{
b=temp.GetString(byt);//read the content from myfile.txt
// The operation about uploading a blob .........
}
return b;
}
return b;
}
You could see the result like this:
In Asp.Net Mvc 6, I am trying to convert image to bytes for adding the picture into database. I cannot find the way to use the right method of encoding. Can someone help me to correct this below code, the mistake is at encoding: UInt32 which is not valid in the given context.
private readonly ApplicationDbContext _context = new ApplicationDbContext();
public int UploadImageInDataBase(IFormFile file, PublisherInfos publisherInfos)
{
publisherInfos.CoverImage = ConvertToBytes(file);
var pubInfos = new PublisherInfos
{
ImageSize = publisherInfos.ImageSize,
FileName = publisherInfos.FileName,
CoverImage = publisherInfos.CoverImage
};
_context.PublisherInfos.Add(pubInfos);
int i = _context.SaveChanges();
if (i == 1)
{
return 1;
}
else
{
return 0;
}
}
// ConvertToBytes
private byte[] ConvertToBytes(IFormFile image)
{
byte[] CoverImageBytes = null;
var _reader = new StreamReader(image.OpenReadStream());
BinaryReader reader = new BinaryReader(_reader.ReadToEndAsync, encoding: UInt32);
CoverImageBytes = reader.ReadBytes((int)image.Length);
return CoverImageBytes;
}
// Controller
public IActionResult Create(PublisherInfos publisherInfos)
{
if (ModelState.IsValid)
{
IFormFile file = Request.Form.Files["CoverImage"];
PublisherInfosRepository service = new PublisherInfosRepository();
int i = service.UploadImageInDataBase(file, publisherInfos);
if (i == 1)
{
// Add file size and file name into Database
_context.PublisherInfos.Add(publisherInfos);
_context.SaveChanges();
return RedirectToAction("Index", new { Message = PublisherInfoMessageId.DataloadSuccess });
}
}
return View(publisherInfos);
}
You Controller Action will be like this
[HttpPost]
public virtual ActionResult Index(HttpPostedFileBase file)
{
.....
.....
byte[] m_Bytes = ReadToEnd (file.InputStream);
....
...
}
The Helper Method
public static byte[] ReadToEnd(System.IO.Stream stream)
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
If you are using MVC 5
use this
private byte[] ConvertToBytes(IFormFile file)
{
Stream stream= file.OpenReadStream();
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
try this
private byte[] ConvertToBytes(IFormFile image)
{
byte[] CoverImageBytes = null;
BinaryReader reader = new BinaryReader(image.OpenReadStream());
CoverImageBytes = reader.ReadBytes((int)image.Length);
return CoverImageBytes;
}
Iam using CefSharp's SchemeHandler in order to grab resources from my C# project like .css, .js or .png files using a custom url for example custom://cefsharp/assets/css/style.css
I've 2 custom classes in order to archive this.
First class, MyCustomSchemeHandlerFactory will be the one that handles the custom Scheme and it looks like this, where "custom" will be the custom scheme:
internal class MyCustomSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "custom";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new MyCustomSchemeHandler();
}
}
The next class I've implemented is MyCustomSchemeHandler which will receive the call and output a response and it looks like this:
internal class MyCustomSchemeHandler : IResourceHandler
{
private static readonly IDictionary<string, string> ResourceDictionary;
private string mimeType;
private MemoryStream stream;
static MyCustomSchemeHandler()
{
ResourceDictionary = new Dictionary<string, string>
{
{ "/home.html", Properties.Resources.index},
{ "/assets/css/style.css", Properties.Resources.style}
};
}
public Stream Stream { get; set; }
public int StatusCode { get; set; }
public string StatusText { get; set; }
public string MimeType { get; set; }
public NameValueCollection Headers { get; private set; }
public Stream GetResponse(IResponse response, out long responseLength, out string redirectUrl)
{
redirectUrl = null;
responseLength = -1;
response.MimeType = MimeType;
response.StatusCode = StatusCode;
response.StatusText = StatusText;
response.ResponseHeaders = Headers;
var memoryStream = Stream as MemoryStream;
if (memoryStream != null)
{
responseLength = memoryStream.Length;
}
return Stream;
}
public bool ProcessRequestAsync(IRequest request, ICallback callback)
{
// The 'host' portion is entirely ignored by this scheme handler.
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
string resource;
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
var resourceHandler = ResourceHandler.FromString(resource);
stream = (MemoryStream)resourceHandler.Stream;
var fileExtension = Path.GetExtension(fileName);
mimeType = ResourceHandler.GetMimeType(fileExtension);
callback.Continue();
return true;
}
else
{
callback.Dispose();
}
return false;
}
void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl)
{
responseLength = stream == null ? 0 : stream.Length;
redirectUrl = null;
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusText = "OK";
response.MimeType = mimeType;
}
bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
{
//Dispose the callback as it's an unmanaged resource, we don't need it in this case
callback.Dispose();
if (stream == null)
{
bytesRead = 0;
return false;
}
//Data out represents an underlying buffer (typically 32kb in size).
var buffer = new byte[dataOut.Length];
bytesRead = stream.Read(buffer, 0, buffer.Length);
dataOut.Write(buffer, 0, buffer.Length);
return bytesRead > 0;
}
bool CanGetCookie(Cookie cookie)
{
return true;
}
bool CanSetCookie(Cookie cookie)
{
return true;
}
void Cancel()
{
}
}
Inside this class I've defined a custom resource dictionary which will dictate what file from the resources will be used, so as I stated in the first example, custom://cefsharp/assets/css/style.css should load the resource Properties.Resources.style, the problem is that nothing gets loaded once I enter to the specific url, I've tried to output the mimeType and It works but somehow the file itself won't output correctly. Is there something wrong with my implementation?
Additionaly I've tried to output the raw file in the form of:
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
MessageBox.Show(resource);
}
And it outputs the correct file without any problems.
To load the custom Scheme I use the following code before initializing CefSharp:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = MyCustomSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new MyCustomSchemeHandlerFactory()
});
The above classes were based on the following links:
MyCustomSchemeHandlerFactory: FlashResourceHandlerFactory.cs
MyCustomSchemeHandler: CefSharpSchemeHandler.cs and ResourceHandler.cs
Since Cefsharp changed a bit in last few months here is an updated and easier way of handling 'file' protocol. I wrote blog post on this matter.
What you want to add is your scheme handler and its factory:
using System;
using System.IO;
using CefSharp;
namespace MyProject.CustomProtocol
{
public class CustomProtocolSchemeHandler : ResourceHandler
{
// Specifies where you bundled app resides.
// Basically path to your index.html
private string frontendFolderPath;
public CustomProtocolSchemeHandler()
{
frontendFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./bundle/");
}
// Process request and craft response.
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
var requestedFilePath = frontendFolderPath + fileName;
if (File.Exists(requestedFilePath))
{
byte[] bytes = File.ReadAllBytes(requestedFilePath);
Stream = new MemoryStream(bytes);
var fileExtension = Path.GetExtension(fileName);
MimeType = GetMimeType(fileExtension);
callback.Continue();
return true;
}
callback.Dispose();
return false;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}
}
And then register it before calling Cef.Initialize:
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});
If you simply need to return a string, then you can use ResourceHandler.FromString(html, mimeType). For this you just need to implement the ISchemeHandlerFactory.
https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp/ResourceHandler.cs#L98
Example reading from a file https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp.Example/CefSharpSchemeHandlerFactory.cs#L17 which can be translated to reading from a string quite simply.
I have the following code which tries to upload the picture to picasa website. when I m trying to upload I m getting Unauthorised access exception. I dont know how to get the AuthToken.
Here is my code . Please let me know if you have any clues.
public delegate void UploadPhotoCallback(bool success, string message);
public static void UploadPhoto(string albumId, string originalFileName, byte[] photo, UploadPhotoCallback callback)
{
string Username = "mailmugu";
string AuthToken = "";
try
{
var url = string.Format("http://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}", Username, albumId);
var request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
//request.ContentType = HttpFormPost.ImageJpeg;
//request.Method = HttpMethods.Post;
request.ContentType = "image/jpeg";
request.Method = "POST";
request.Headers[HttpRequestHeader.Authorization] = "GoogleLogin auth=" + AuthToken;
request.BeginGetRequestStream(new AsyncCallback(UploadGetRequestCallback),
new UploadRequestState
{
Request = request,
Callback = callback,
Photo = photo,
FileName = originalFileName
});
}
catch (Exception e)
{
Console.WriteLine(e);
//throw new MyException(MyResources.ErrorUploadingPhotoMessage, e);
}
}
private static void UploadGetRequestCallback(IAsyncResult ar)
{
try
{
var state = (UploadRequestState)ar.AsyncState;
HttpWebRequest request = state.Request;
// End the operation
var stream = request.EndGetRequestStream(ar);
stream.Write(state.Photo, 0, state.Photo.Length);
stream.Close();
request.BeginGetResponse(UploadGetResponseCallback, state);
}
catch (Exception e)
{
//throw new MyException(MyResources.ErrorUploadingPhotoMessage, e);
}
}
private static void UploadGetResponseCallback(IAsyncResult ar)
{
UploadRequestState state = null;
try
{
state = (UploadRequestState)ar.AsyncState;
HttpWebRequest request = state.Request;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
if (response != null)
{
response.Close();
}
if (state.Callback != null)
{
MessageBox.Show("Uploaded Sucessfully");
//state.Callback(true, MyResources.PhotosUploadedMessage);
}
}
catch (Exception e)
{
MessageBox.Show("Error" + e.Message);
Console.Write(e);
//if (state != null && state.Callback != null)
//state.Callback(false, MyResources.ErrorSavingImageMessage);
}
}
public class UploadRequestState
{
public HttpWebRequest Request { get; set; }
public UploadPhotoCallback Callback { get; set; }
public byte[] Photo { get; set; }
public string FileName { get; set; }
}
private void button1_Click(object sender, RoutedEventArgs e)
{
string albumId = "Picasa";
string Filename = "Test";
UploadRequestState _uploadReq = new UploadRequestState();
Uri myuri = new Uri("/Images/Test.jpg", UriKind.RelativeOrAbsolute);
BitmapImage btmMap = new BitmapImage(myuri);
image1.Source=btmMap;
WriteableBitmap bmp = new WriteableBitmap(btmMap.PixelWidth,btmMap.PixelHeight);
MemoryStream ms = new MemoryStream();
// write an image into the stream
Extensions.SaveJpeg(bmp, ms,
btmMap.PixelWidth, btmMap.PixelHeight, 0, 100);
byte[] Photo = ms.ToArray();
UploadPhoto(albumId,Filename,Photo,_uploadReq.Callback);
}
}
}
Since your code does not even attempt to get the Authentication Token required to do what you want I suggest looking at http://code.google.com/apis/picasaweb/docs/2.0/developers_guide_protocol.html#Auth and open a new question to address any concerns you might have.