c# Webclient.UploadData works on local, but fails on server - c#

I am trying to deploy a website but am having an error with one of my forms that has an image upload.
Firstly i am using NetworkSolutions for the hosting, and one of the forms has an file upload input for images. When I run the application locally and upload the image to the FTP, everything works correctly, however when i deploy to the server, the connection appears to timeout (since it hangs for a few moments), than i get the message "Object reference not set to an instance of an object.". One thing i should note is SSL is not setup on this server, however i am using an unsecure port.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Submit(RegistrationViewModel viewModel)
{
if (!ModelState.IsValid)
{
return RedirectToAction("Index", viewModel);
}
if (Request.Files.Count > 0)
{
string path = String.Empty;
HttpPostedFileBase file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
string fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName); // Path.GetFileName(file.FileName);
try
{
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential("***", "***");
byte[] buffer = new byte[file.ContentLength];
file.InputStream.Read(buffer, 0, buffer.Length);
file.InputStream.Close();
path = "ftp://***.***.com:21/pics/" + fileName;
client.UploadData(path, buffer);
}
}
catch (WebException ex)
{
string status = ((FtpWebResponse)ex.Response).StatusDescription;
}
}
Context.Registrations.Add(new Registration
{
FirstName = viewModel.FirstName,
LastName = viewModel.LastName,
Email = viewModel.Email,
PhoneNumber = viewModel.PhoneNumber,
Age = viewModel.Age,
ImagePath = path,
CreatedDate = DateTime.Now
});
await Context.SaveChangesAsync();
ConfirmationViewModel confirmViewModel = new ConfirmationViewModel
{
FirstName = viewModel.FirstName,
LastName = viewModel.LastName,
Email = viewModel.Email,
PhoneNumber = viewModel.PhoneNumber
};
return RedirectToAction("Confirm", "Register", confirmViewModel);
}
}
I expect that the image should save to the path as it does locally, however on the server i cannot get pass this timeout/null exception. The exception in the stack trace is when the method UploadData hits, in the register controller line 89 (im showing the Submit function in the register controller). Since this issue is happening on the server, getting feedback on the error has been fairly limiting. Removing the try/catch i get internal server error, with the try catch, i get Null reference exception.
One thing i tried was removing the lines assuming something was null here, but same result:
file.InputStream.Read(buffer, 0, buffer.Length);
file.InputStream.Close();
Any help would be greatly appreciated.

I have tracked down the Object reference not set to an instance of an object exception comes from the catch statement. The exception does not seem to be a WebException, or at least the response i was casting was not an FtpWebResponse. (very difficult to debug since i have to deploy each time), however i am still timing out for some unknown reason.

I have successfully saved the image to the server from the server! The issue came down to the request being made specifically from the web server domain to the ftp domain.
Hidden in NetworkSolution options was folder privileges (Security/Password Protection for anyone looking), after allowing write access on the directory i needed, i switched my method to use the HttpPostedFileBase to save the file directly to the server, and success! I wish I was able to find that option from the start and save hours of headache.

Related

Can't configure credentials WCF with basic realm?

I have added a Connected Reference in Visual Studio 2019. It consumed a https endpoint, and created all binding information needed into a reference.cs file.
It didn't generate any App.config file, so I suspected what I needed was bundled into the reference.cs file. Indeed, looking into it, it mostly was.
So I tried creating a client, specify client credentials in two ways, as you can see, but still, doesn't matter how I specify it, I get an exception when calling this code below.
public async Task SendFile(Stream fileStream, string fileName, Guid machineKey)
{
_logger.LogInformation("Starting file sending to Manager 1.");
_logger.LogInformation($"Sending file {fileName} from Machine {machineKey}");
try
{
var client = new FileTransferClient(FileTransferClient.EndpointConfiguration.BasicHttpBinding_IFileTransfer, _options.FileTransferEndPoint)
{
ClientCredentials =
{
UserName =
{
UserName = _options.FileTransferUsername,
Password = _options.FileTransferPassword
}
}
};
client.ClientCredentials.UserName.UserName = _options.FileTransferUsername;
client.ClientCredentials.UserName.Password = _options.FileTransferPassword;
using (new OperationContextScope(client.InnerChannel))
{
}
await client.UploadAsync(new FileUploadMessage
{
// Assume that this is enough. Can't really supply file length...
FileInfo = new FileTransferInfo
{
TransferId = new Guid(),
MachineUUID = machineKey.ToString(),
Name = fileName
},
TransferStream = fileStream
});
}
catch (Exception e)
{
_logger.LogError("An unexpected exception occurred while sending file to Manager 1G.", e);
}
_logger.LogInformation("File sending finished.");
}
The exception is "The HTTP request is unauthorized with client authentication scheme 'Basic'. The authentication header received from the server was 'Basic Realm'."
I have compared to similar APIs that use the beforementioned App.config, and have edited the reference.cs to match the security I think it should have.
Specifically, I've added the security related lines here:
private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
{
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IFileTransfer))
{
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
result.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
result.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
return result;
}
if ((endpointConfiguration == EndpointConfiguration.MetadataExchangeHttpsBinding_IFileTransfer))
{
System.ServiceModel.Channels.CustomBinding result = new System.ServiceModel.Channels.CustomBinding();
System.ServiceModel.Channels.TextMessageEncodingBindingElement textBindingElement = new System.ServiceModel.Channels.TextMessageEncodingBindingElement();
result.Elements.Add(textBindingElement);
System.ServiceModel.Channels.HttpsTransportBindingElement httpsBindingElement = new System.ServiceModel.Channels.HttpsTransportBindingElement();
httpsBindingElement.AllowCookies = true;
httpsBindingElement.MaxBufferSize = int.MaxValue;
httpsBindingElement.MaxReceivedMessageSize = int.MaxValue;
result.Elements.Add(httpsBindingElement);
return result;
}
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
}
What I found dumbfounding, was that with embedding in the constructor calling setting the ClientCredentials, they were not in any way populated when I inspected the client with a debug session attached. Hence I tried to set it afterwards specifically.
But either way, the end result is the same, get the same error.
How can I resolve that error in Code?
I can in theory try to add an App.config and do it there, but I don't know the Contract. And I am not sure what to look for in the generated reference.cs to identify it. So I'd prefer to learn to do this by Code, as the Contract is already in place there, and I can supply the endpoint via the _options, so it should be able to configure for different environments by that.
Turned out I had indeed password and username exchanged, so fixing that helped me get past of this issue.

Rotativa not working when impersonate enabled on server

I am using Rotativa to generate a PDF from a view. It works on my localhost, but when I push to my server it does not work at all. The Server has Windows Authentication and Impersonate enabled which I need to have for this site.
This is the error I get when I try to run the code on the server
Qt: Could not initialize OLE (error 80070005) Error: Failed loading
page
https://api.mydomain.com/Reports/RedBluePDF?community=CommunityName&procedure=GetTasks
(sometimes it will work just to ignore this error with
--load-error-handling ignore) Exit with code 1 due to http error: 1003
Here is my code:
public byte[] getReportsPDF(string community, string procedure)
{
byte[] pdfBytes = new byte[] { };
RouteData route = new RouteData();
route.Values.Add("controller", "SiteSuperReports");
route.Values.Add("action", "RedBluePDF");
this.ControllerContext = new ControllerContext(new HttpContextWrapper(System.Web.HttpContext.Current), route, this);
if (procedure == "GetProductionTasks")
{
var actionPDF = new Rotativa.ActionAsPdf("RedBluePDF", new { community = community, procedure = procedure })
{
PageSize = Size.A4,
PageOrientation = Rotativa.Options.Orientation.Landscape,
PageMargins = { Left = 1, Right = 1 }
};
try
{
pdfBytes = actionPDF.BuildFile(ControllerContext);
}
catch(Exception e)
{
Console.Write(e.Message.ToString());
}
}
return pdfBytes;
}
And here is RedBluePDF Method, this just returns a View:
public ActionResult RedBluePDF(string community, string procedure) {
return View();
}
What am I doing wrong and how come this is not working on my server, but is on my localhost? And How do I get it work on my server.
Try one of this solutions:
1- Go to IIS > Site > Authentication, click on "ASP.NET Impersonation" and DISABLE it.
2- If you're calling a script or a file or whatever, specify the used protocol:
src="//api.mydomain.com/?????
to:
src="http://api.mydomain.com/?????
3- In your Application Pool's configuration, under Process Model, there's an option "Load User Profile". It comes as False by default, set it as true.

Download File through headers from different server

I have PDF file placed on different (FILE-Server) server machine, and the IIS machine on which my MVC application is hosted have rights to that File-Server. From IIS machine i can access the file through following URI:
file://file-server/data-folder/pdf/19450205.pdf
I want to enable my MVC app's users to download their respective files by clicking on download link or button. So probably i would have to write some Action for that link/button.
I tried to use File return type for my Action method in following way:
public ActionResult FileDownload()
{
string filePth = #"file://file-server/data-folder/pdf/19450205.pdf";
return File(filePth , "application/pdf");
}
but the above code gives exception of URI not supported.
I also tried to use FileStream to read bytes inside array return that bytes towards download, but FileStream also gives error of not proper "Virtual Path" as the file is not placed inside virtual path, its on separate server.
public ActionResult Download()
{
var document = = #"file://file-server/data-folder/pdf/19450205.pdf";
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = document.FileName,
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(document.Data, document.ContentType);
}
Thanks for the replies, but both suggestion did not work.
as file needs to be accessed over URI, using FileInfo gives error: URI formats are not supported.
I managed to get this done through following mechanism:
public ActionResult FaxFileDownload()
{
string filePth = #"file://file-server/data-folder/pdf/19450205.pdf";
WebClient wc = new WebClient();
Stream s = wc.OpenRead(filePth);
return File(s, "application/pdf");
}
Thanks to All.

Write uploaded file to linux server from asp.net mvc 4.0 application

I want to upload an uploaded file to both where my mvc 4.0 application runs and to another server that is powered by linux based server. I want to upload file to directory under tomcat server(ex: KGS/assets/). I can upload file to local server by the following code
public ActionResult Upload(string qqfile, int id)
{
//resim ekliyor
const string path = #"C:\Temp\";
const string kgsPath =#"\\";
try
{
var stream = Request.InputStream;
string file;
if (String.IsNullOrEmpty(Request["qqfile"]))
{
// IE
HttpPostedFileBase postedFile = Request.Files[0];
stream = postedFile.InputStream;
file = Path.Combine(path, System.IO.Path.GetFileName(Request.Files[0].FileName));
}
else
{
//Webkit, Mozilla
file = Path.Combine(path, qqfile);
}
var buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
System.IO.File.WriteAllBytes(file, buffer);
}
catch (Exception ex)
{
return Json(new { success = false, message = ex.Message }, "application/json");
}
return Json(new { success = true }, "text/html");
}
Are there anyways or approaches to achieve this or is this impossible to be done?
You must expose some way of storing the file on the Linux server that your ASP.NET application can use. This could be a Samba or NFS share, an FTP account, a web service, etc. The storage mechanism you choose will dictate how you store the file there.
Another option would be to use something like rsync to keep files in both places synchronized. Your .NET application would be unaware of this, so no coding required.

Why did not redirect to view in ASP.NET MVC 4

All, I have a controller which saved the posted file(Please review below code). It took about 20-30 min to finish it. But I found after saving the file, the RedirectToAction didn't work. the IE status bar shown :
Waiting for http://......./index.
BTW, My session state is stored in SQL Server. And timeout is 300 Mins. I am not sure this problem if has relationship with IIS 7 app pool idle time which I post here before.
Although it didn't redirect to the action ,I found the session still exists.
The file and the record were saved successfully .Only problem is It didn't redirect.
please help me .thanks.
[HttpPost]
[AcceptButton("Upload")]
public ActionResult Upload(UploadPackageModel model)
{
//after about 20-30 min for 160MB file-upload, runs here.
DeployLogModel tempLog = null;
try
{
if (Request.Files.Count > 0 && Request.Files[0].ContentLength > 0)
{
var file = Request.Files[0];
var fileName = Path.GetFileName(file.FileName);
string sUploadFullPath = string.Empty;
model.ID = Guid.NewGuid();//PK id of Uploaded Package
string sUploadFileName = model.ID + Path.GetExtension(file.FileName);
model.CreatedBy = DataHelp.LoginAdministrator.ID.ToString();
model.LastUpdatedBy = DataHelp.LoginAdministrator.ID.ToString();
model.PackageSize = Request.Files[0].ContentLength;
model.CreatedDate = DateTime.UtcNow;
model.LastUpdatedDate = DateTime.UtcNow;
model.PackageName = fileName;
string rootPath = AppDomain.CurrentDomain.BaseDirectory + "\\" + "DeployPackages\\";
sUploadFullPath = Path.Combine(rootPath, sUploadFileName);
model.PackagePath = sUploadFullPath;
if (!Directory.Exists(rootPath))
Directory.CreateDirectory(rootPath);
file.SaveAs(sUploadFullPath);//Save the uploaded package.
model.SavePackInfoIntoDB(model);//Save record to DB
}
}
catch (Exception ex)
{
Log.Write("-Upload-Package-failed-:\r\n" + ex.Message + "\r\n" + ex.StackTrace);
}
return RedirectToAction("Index");//does not work.
}
The file and the record were saved successfully .Only problem is It didn't redirect.
Update:
Web.config httpRuntime setting is:
<httpRuntime executionTimeout="14400" maxRequestLength="716800" />
Edited to add Index action code:
public ActionResult Index(int? page)
{
var db = DbContextHelper.CreateInstance();
//Find all uploaded packages.
var packages = db.DeployPackages.OrderByDescending(x => x.CreatedDate).Select(x => new PackageModel
{
PackageId = x.ID,
UploadedBy = x.CreatedBy,
Description = x.Description,
PackageName = x.PackageName,
PackageSize = x.PackageSize,
PackagePath = x.PackagePath,
UploadTime = x.CreatedDate,
VersionName = x.VersionName
}).ToList();
int pageSize = ConfigHelper.BigPageSizeNum;
int pageNumber = (page ?? 1);
return View(packages.ToPagedList(pageNumber, pageSize));
}
Edited to add Fiddler trace info
result protocol Host Url
200 http test.cloudapp.net /package/upload
200 http test.cloudapp.net /package/index
I can see the response html content in the fiddler for /package/index,but the browser just freeze on the same page(/package/upload) .
I wondered if there is a way to change the windows.location.href with js code ,My idea is when finished upload action successfully. then output to client some script like response.write script in classical asp.net page . the js change windows.location.href to redirect to /package/index. Is there any way to make it in ASP.NET MVC4?
Using Content(sResultScript, "text/html") to output javascript to redirect index url. IE8 shown a failed page , chrome and Firefox is OK .

Categories

Resources