Struts2 Multiple File Upload with Map - file-upload

I am doing Multiple file upload with Struts2. It was working fine I map with java static action properties. But I am using Map to collect all the files. I am getting only the file object. I am not getting the fileName and content type.
public class TableListAction extends ActionSupport
{
private Map raja;
public Map getRaja()
{
return raja;
}
public void setRaja(Map raja)
{
this.raja = raja;
}
public String upload() throws Exception
{
System.out.println(raja);
return SUCCESS;
}
}
My Jsp like this
<s:form enctype="multipart/form-data" method="post" action="upload">
<s:file name="raja['column']"></s:file>
<s:file name="raja['column']"></s:file>
<s:file name="raja['column']"></s:file>
<s:file name="raja['column']"></s:file>
<s:submit/>
During uploading I am getting the file object array in that raja Map but I am not getting the fileName and contenttype.
Thanks in Advance
regards
Shreeram A

<s:form enctype="multipart/form-data" method="post" action="upload">
<s:file name="raja.column"></s:file>
<s:file name="raja.column"></s:file>
<s:file name="raja.column"></s:file>
<s:file name="raja.column"></s:file>
<s:submit/>
They are append name attribute with FileName and ContentType.
I used before name like this raja['column'], so the result raja['column']FileName and
raja['column']ContentType. It wont come into the the Map.
Then i modified raja.column. Then it will append FileName and ContentType correctly like raja.columnContentType and raja.columnFileName
Its work fine now.
Thanks
Shreeram A

Related

EditorFor Tag Helper doesn't render validation attributes when using FluentValidator

I have a simple form like this which makes use of the #Html.EditorFor extension:
<form method="post">
#Html.EditorFor(x => x.SystemSettings.EmailFromAddress)
<submit-button title="Save"></submit-button>
</form>
I want to take advantage of .NET Core's tag helpers so that my form looks like this instead:
<form method="post">
<editor asp-for="SystemSettings.EmailFromAddress"/>
<submit-button title="Save"></submit-button>
</form>
I also eventually would like to have my own custom tag helpers so I can do something like this instead:
<text-box asp-for="SystemSettings.EmailFromAddress"></text-box>
I have a string template which gets rendered by the #Html.EditorFor extension:
#model string
<div class="form-group">
<label asp-for="#Model" class="m-b-none"></label>
<span asp-description-for="#Model" class="help-block m-b-none small m-t-none"></span>
<div class="input-group">
<input asp-for="#Model" class="form-control" />
<partial name="_ValidationIcon" />
</div>
<span asp-validation-for="#Model" class="validation-message"></span>
</div>
To do that, I saw someone implemented an EditorTagHelper, which looks like this:
[HtmlTargetElement("editor", TagStructure = TagStructure.WithoutEndTag,
Attributes = ForAttributeName)]
public class EditorTagHelper : TagHelper
{
private readonly IHtmlHelper _htmlHelper;
private const string ForAttributeName = "asp-for";
private const string TemplateAttributeName = "asp-template";
[HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; }
[HtmlAttributeName(TemplateAttributeName)]
public string Template { get; set; }
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public EditorTagHelper(IHtmlHelper htmlHelper)
{
_htmlHelper = htmlHelper;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (output == null)
throw new ArgumentNullException(nameof(output));
if (!output.Attributes.ContainsName(nameof(Template)))
{
output.Attributes.Add(nameof(Template), Template);
}
output.SuppressOutput();
(_htmlHelper as IViewContextAware).Contextualize(ViewContext);
output.Content.SetHtmlContent(_htmlHelper.Editor(For.Name, Template));
await Task.CompletedTask;
}
}
When I use the EditorTagHelper though, it seems to be missing the unobtrusive Javascript validation attributes:
Using #Html.EditorFor, this gets rendered:
<input class="form-control valid" type="text" data-val="true" data-val-required="Email From Address cannot be empty" id="SystemSettings_EmailFromAddress" name="SystemSettings.EmailFromAddress" value="whatever#test.com" aria-required="true" aria-invalid="false" aria-describedby="SystemSettings_EmailFromAddress-error">
It's got the data-val attributes so client-side validation gets applied.
When I use the EditorTagHelper instead, this gets rendered:
<input class="form-control valid" type="text" id="SystemSettings_EmailFromAddress" name="SystemSettings.EmailFromAddress" value="whatever#test.com" aria-invalid="false">
The unobtrusive validation attributes are not being applied. I am using FluentValidation and I have specified an AbstractValidator like this:
public class SystemSettingsValidator : AbstractValidator<SystemSettings>
{
public SystemSettingsValidator()
{
RuleFor(x => x.EmailFromAddress).NotEmpty()
.WithMessage("Email From Address cannot be empty");
}
}
I found that if I removed the AbstractorValidator and simply added a [Required] attribute to my model property the validation then works properly. This suggests that there is something wrong with FluentValidation. Perhaps there is a configuration issue.
I am using Autofac dependency injection to scan my assemblies and register validator types:
builder.RegisterAssemblyTypes(Assembly.Load(assembly))
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces()
.PropertiesAutowired()
.InstancePerLifetimeScope();
This seems to work fine. In case it wasn't fine, I also tried registering the validators from the fluent validation options like this:
.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblies(new List<Assembly>
{Assembly.GetExecutingAssembly(), Assembly.Load(nameof(Entities))});
})
This also seemed to be fine.
One thing to note is that an earlier problem I had was that using Autofac assembly scanning was breaking the application when tag helpers were included. I added a filter to ensure that tag helpers are not included when registering these dependencies, e.g.
builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web))
.Where(x => !x.Name.EndsWith("TagHelper"));
I have uploaded a working sample of the code here: https://github.com/ciaran036/coresample2
Navigate to the Settings Page to see the field I am trying to validate.
This issue also appears to affect view components.
Thanks.
I believe the issue is in the tag helper, in that it uses IHtmlHelper.Editor rather than IHtmlHelper<TModel>.EditorFor to generate the HTML content. They are not quite the same.
As you point out FluentValidation injects the validation attributes as you'd expect for #Html.EditorFor(x => x.SystemSettings.EmailFromAddress). However for #Html.Editor("SystemSettings.EmailFromAddress"), which is what your custom tag helper is doing, FluentValidation doesn't inject the validation attributes. So that rules out the tag helper itself and moves the problem to the Editor invocation.
I also noticed that Editor doesn't resolve <label asp-for (or the other <span asp-description-for tag helper you're using) so that suggests it's not a FluentValidation specific issue.
I wasn't able to replicate your success with the Required attribute for the custom tag helper/Editor - the Required attribute only injected the validation attributes when using EditorFor.
The internals for Editor and EditorFor are similar but with a key difference, the way they resolve the ModelExplorer instance used to generate the HTML content differs and I suspect this is the problem. See below for these differences.
Things like PropertyName set to null and Metadata.Property not being set for Editor, but set to EmailFromAddress and SystemSettings.EmailFromAddress for EditorFor are standing out as potential causes for the behaviour we're seeing.
The painful part is the tag helper has a valid ModelExplorer instance via the For property. But there is no built in provision to provide it to the html helper.
As to the resolution, the obvious one seems to be to use EditorFor rather than Editor however it doesn't look easy. It'd likely involve reflection and building an expression.
Another option is, considering the tag helper resolves the ModelExplorer correctly, is to extend HtmlHelper and override the GenerateEditor method - what both Editor and EditorFor end up invoking - so you can pass in the ModelExplorer and work around the problem.
public class CustomHtmlHelper : HtmlHelper, IHtmlHelper
{
public CustomHtmlHelper(IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IViewBufferScope bufferScope, HtmlEncoder htmlEncoder, UrlEncoder urlEncoder) : base(htmlGenerator, viewEngine, metadataProvider, bufferScope, htmlEncoder, urlEncoder) { }
public IHtmlContent CustomGenerateEditor(ModelExplorer modelExplorer, string htmlFieldName, string templateName, object additionalViewData)
{
return GenerateEditor(modelExplorer, htmlFieldName, templateName, additionalViewData);
}
protected override IHtmlContent GenerateEditor(ModelExplorer modelExplorer, string htmlFieldName, string templateName, object additionalViewData)
{
return base.GenerateEditor(modelExplorer, htmlFieldName, templateName, additionalViewData);
}
}
Update your tag helper to use it:
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (output == null)
throw new ArgumentNullException(nameof(output));
if (!output.Attributes.ContainsName(nameof(Template)))
{
output.Attributes.Add(nameof(Template), Template);
}
output.SuppressOutput();
(_htmlHelper as IViewContextAware).Contextualize(ViewContext);
var customHtmlHelper = _htmlHelper as CustomHtmlHelper;
var content = customHtmlHelper.CustomGenerateEditor(For.ModelExplorer, For.Metadata.DisplayName ?? For.Metadata.PropertyName, Template, null);
output.Content.SetHtmlContent(content);
await Task.CompletedTask;
}
Finally register the new helper, the earlier the better I'd say
services.AddScoped<IHtmlHelper, CustomHtmlHelper>();
Working solution

IFormFile 'System.InvalidOperationException'

The non-public.member _baseStream attribute in IFormFile in my ASP.NET Core application throws the following exception after uploading a file:
ReadTimeout = ((Microsoft.AspNetCore.Http.Internal.FormFile)BildUpload)._baseStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'
I'm trying to upload a file using a razor page with the following code:
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<input type="file" name="BildUpload" />
</div>
<input type="submit" value="Upload" class="btn btn-default" />
</form>
In the codebehind class I only got the declaration and nothing else read or writes the paramter excepts the razor page:
public IFormFile BildUpload { get; set; }
Thanks for your help!
My final goal is to parse the file to a byte array and sava at to a database like this: How to Convert a file into byte array directly without its path(Without saving file)
But over there I'm getting a nullpointer exception.
You can read about file upload here to make sure that you did not missed any steps and in case you need more knowledge about file upload.
In case someone faces similar behavior. Here's my solution for uploading an image and converting it to a byte array (for storing it in a Microsoft SQL database):
First of all use the xaml code and the IFormFile property from the question.
In the code behind add this code to process the form data to a byte array:
public async Task<IActionResult> OnPostAsync(string id)
{
//get the "Kontakt" entity
if (!await SetKontaktAsync(id))
{
return NotFound();
}
//convert form data to byte array and assign it to the entity
if (BildUpload.Length > 0)
{
using (var ms = new MemoryStream())
{
BildUpload.CopyTo(ms);
Kontakt.Bild = ms.ToArray();
}
}
//save changes to the database
_context.Attach(Kontakt).State = EntityState.Modified;
await _context.SaveChangesAsync();
//reload page
return await OnGetAsync(Kontakt.GID);
}
Frameworks: ASP.NET Core 2.2, Entity Framework Core 2.2

<p:media display pdf from folder dynamically

I have several pdf files saved in ...WebContent/Manuals/filename.pdf that I am trying to display on my page. I am getting "Failed to Load PDF document" message in Chrome.
My Jsf:
<p:media value="#{reviewBean.manual}" player="pdf" height="600px" width="1000px" />
My #SessionScoped Bean:
public StreamedContent getManual() throws IOException {
String type = "application/pdf";
String path = "";
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
path = "C:\\.....\\WebContent\\Manuals\\filename.pdf";
InputStream is = new ByteArrayInputStream(path.getBytes());
return new DefaultStreamedContent(is, type);
}
}
There is additional logic that i have left out for clarity which decides which pdf is displayed.
I have also tried the file path of /Manuals/filename.pdf as path
I tried following the below example:
How to bind dynamic content using <p:media>?
In my case I do not need to retrieve a value using <f:param
Is my file path incorrect to display the image? Or am I building the Stream incorrectly? Any guidance is much appreciated.
I solved this by merely returning the url as a String.
public String getManual() {
return user.getManuals().get(user.getLData().getDepart());
}
Where the returned value is the file path of the pdf: Manuals/filename.pdf

Simple controller which takes POST is not found

I've made some previous question asking for the help with the problems since I updated MVC4 webapi beta to RC. I got most in order now, but here's one I cannot figure out the reason for yet.
For this simple controller I have one which accepts a POST and one that accepts GET. When I try to run those by sending request from a HTML form, only the GET controller is found while the POST one will return me the following error.
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost/webapi/api/play/test'.",
"MessageDetail": "No action was found on the controller 'Play' that matches the name 'test'."
}
Why is the POST controller not found?
Controllers
public class PlayController : ApiController
{
[HttpPost] // not found
public string Test(string output)
{
return output;
}
[HttpGet] // works
public string Test2(string output)
{
return output;
}
}
HTML form
<form action="http://localhost/webapi/api/play/test" method="post">
<input type="text" name="output" />
<input type="submit" name="submit" />
</form>
<form action="http://localhost/webapi/api/play/test2" method="get">
<input type="text" name="output" />
<input type="submit" name="submit" />
</form>
Web.API is a little bit picky when you want to post "simple" values.
You need to use the [FromBody] attribute to signal that the value is not coming from the URL but from the posted data:
[HttpPost]
public string Test([FromBody] string output)
{
return output;
}
With this change you won't get 404 anymore but output will be always null, because Web.Api requries the posted values in special format (look for the Sending Simple Types section):
Second, the client needs to send the value with the following format:
=value
Specifically, the name portion of the name/value pair must be empty for a simple type. Not >all browsers support this for HTML forms,
but you create this format in script...
So recommend that you should create a model type:
public class MyModel
{
public string Output { get; set; }
}
[HttpPost]
public string Test(MyModel model)
{
return model.Output;
}
Then it will work with your sample froms without modifing your views.

How to deploy ActiveX dll from web page

Been trying off and on for days now and can't figure this out. I have written a C# class file for an Intranet app to control the local serial ports. It works great when I manually register the dll using regasm, however, I need to deploy this control from a web page without having to manually register it. I tried creating a Setup Project in Visual Studio 2010, it compiled fine yet I can not open the object in a webpage.
Here are the pertinent lines of code from my C# class:
namespace wmsSerialPorts
{
[Guid("55D31498-12A5-4FF0-942D-3B0BA449CA7B")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface iAxDevices
{
[DispId(1)]
int OpenPort(string sComPort);
[DispId(2)]
int ClosePort();
[DispId(3)]
int SendCmd(string sCmd);
[DispId(4)]
string GetLastError();
//[DispId(5)]
//string ReadLine();
[DispId(6)]
string ReadWeight();
[DispId(7)]
Microsoft.JScript.ArrayObject GetJsPorts();
[DispId(8)]
void prtLabel(string sItemNum, string sQty, string sDesc, string sWoNum, string sBoxID, string sBoxIDBarCode, string sBoxIDorig);
[DispId(9)]
void prtLabelQC(string sItemNum, string sQty, string sDesc, string sWoNum, string sBoxID, string sBoxIDBarCode, string sBoxIDorig, string sNeedDate, string sRecOverride);
[DispId(10)]
void prtReset();
}
[Guid("E59C5B7E-EF1F-4241-A9FD-191EF8FCC167")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[ProgId("AxDevices")]
public class AXDevices : wmsSerialPorts.SerialCom, iAxDevices, wmsSerialPorts.IObjectSafety
As I mentioned, if I use regasm wmsSerialPorts.dll, the object works great when called from JavaScript like this:
myAx = new ActiveXObject("AXDevices");
My Setup project contains a wmsSerialPorts.inf file:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Setup Hooks]
install=install
[install]
run=msiexec.exe /package """%EXTRACT_DIR%\ActiveXSetup.msi""" /qn
.... and an ActiveXBuild.ddf file:
.Set DiskDirectoryTemplate=cab
.Set CabinetNameTemplate=ActiveXSetup.cab
Debug\ActiveXSetup.msi
wmsSerialPorts.inf
My wmsSerialPorts.dll file is properly referenced as a detached asseembly and building the Setup Project created the ActiveXSetup.cab and ActiveXSetup.msi files as expected.
I then created this HTML page to load the object:
<!DOCTYPE>
<html>
<head>
<title>Test</title>
</head>
<body>
<!-- <object id="AXDevices" classid="clsid:E59C5B7E-EF1F-4241-A9FD-191EF8FCC167" codebase="https://10.0.2.53/BIDWMS/ActiveXSetup.cab">
</object>-->
<object id="AXDevices" classid="clsid:E59C5B7E-EF1F-4241-A9FD-191EF8FCC167" codebase="ActiveXSetup.cab">
</object>
<script type="text/javascript">
try {
var obj = document.AXDevices;
if (obj) {
alert(obj.SayHello());
} else {
alert("Object is not created!");
}
} catch (ex) {
alert("Error message is: " + ex.Description);
}
</script>
</body>
</html>
... but when I run the page, it generates an error of "undefined" (from the catch(ex) block). Any ideas? Thanks in advance ....... Bob
Your Codebase has to be a url, not just a filename. If your file is in C:\inetpub\myCabFiles\ActiveXSetup.cab, and your website is in C:\inetpub, then codebase should be something like
codebase="www.mywebsite.com\myCabFiles\ActiveXSetup.cab"