Am trying to render a list of media images.
In my view I have:
View
#section pageSpecificJsBody {
<script src="/scripts/casestudieslist.js"></script>
<script>
$(function () { pdms.caseStudiesList.init(); });
</script>
}
Which is used to call a js file
The js file calls the following controller
Controller
[HttpGet]
public JsonResult List()
{
var CaseStudyContentTypeId = Services.ContentTypeService.GetContentType("CaseStudy").Id;
var CaseStudies = Services.ContentService.GetContentOfContentType(CaseStudyContentTypeId).Select(x => new CaseStudy {
BannerImage = Umbraco.Content(x.Id).GetPropertyValue("bannerimage"),
Url = Umbraco.Content(x.Id).Url.ToString(),
SectorName = Umbraco.Content(x.GetValue("selectSector")).Name, //x.GetValue("selectSector").ToString(),
BodyTextHeading = x.GetValue("bodyTextHeading").ToString(),
BannerHeading = x.GetValue("bannerheading").ToString()
});
Model
public class CaseStudy
{
public string SectorName { get; set; }
//public int Id { get; set; }
public string Url { get; set; }
public string BannerHeading { get; set; }
public string BannerImage { get; set; }
public string BodyTextHeading { get; set; }
}
Previously the Banner Image was using a media picker so the images could be accessed through Umbraco.Content, but I have now set them all to use a custom cropper which set them to media types
My question is... how can I now set the BannerImage property to get the relevant media image?
normally I could do something similar to this in a view.
var BannerImage = Model.Content.GetPropertyValue("bannerimage");
var MediaImage = Umbraco.TypedMedia((int)BannerImage);
<source srcset="#MediaImage.GetCropUrl("desktopMax")" />
But I don't have access to the model since am in the controller, and am really stuck, am still new to Umbraco and don't yet fully understand everything, so sorry if things are not clear.
Thanks in advance
You can get the #Umbraco helper in a lot of places (including the controller) by doing:
UmbracoHelper umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
I would probably rewrite your code to look like this:
var caseStudies = from caseStudy in Services.ContentService.GetContentOfContentType(CaseStudyContentTypeId)
let content = umbracoHelper.TypedContent(caseStudy.Id)
let bannerImage = umbracoHelper.TypedMedia(caseStudy.GetPropertyValue("bannerimage"))
let sector = umbracoHelper.TypedContent("selectSector")
select new CaseStudy {
BannerImage = bannerImage.Url,
Url = content.Url,
SectorName = sector.Name,
BannerHeading = caseStudy.GetPropertyValue<string>("bannerheading"),
BodyTextHeading = caseStudy.GetPropertyValue<string>("bodyTextHeading"
};
I found this post Here, which has a good suggestion on obtaining the crop url for an image.
Here's what I've wrote to solve the issue:
Controller
var CaseStudyContentTypeId = Services.ContentTypeService.GetContentType("CaseStudy").Id;
var CaseStudies = Services.ContentService.GetContentOfContentType(CaseStudyContentTypeId).Select(x => new CaseStudy
{
BannerImage = Umbraco.TypedMedia(x.GetValue<int>("bannerimage")).GetCropUrl("umbracoFile", "mobile"),
Url = Umbraco.Content(x.Id).Url.ToString(),
SectorName = Umbraco.Content(x.GetValue("selectSector")).Name, //x.GetValue("selectSector").ToString(),
BodyTextHeading = x.GetValue("bodyTextHeading").ToString(),
BannerHeading = x.GetValue("bannerheading").ToString()
});
Am going to debug and test out Sams method so I can work out the difference between both examples. If anyone (or Sam) could offer suggestions as to why they believe one way could potentially be more beneficial than the other please could you give an explanation.
Thanks in advance.
Related
This is to submit a view that uses ajax to pull the data.
I am trying to retrieve an image from MongoDb GridFS bucket. The download operation works. But the issue is, the view model that I use has:
public User User { get; set; }
public List<IFormFile> ImageUpload { get; set; }
I get the user from the db context, and use that to identify the image from the bucket and I want to return it to the view from the controller.
The following is my controller code:
public IActionResult AddEditUser(int id = 0)
{
if (id == 0)
{
return View(new UserImgBinder());
}
else
{
var userImageId = _context.User.Where(x => x.UserId.Equals(id)).Select(y => y.AvatarImg).ToString();
var stream = ContextNew.ImagesBucket.OpenDownloadStream(new ObjectId(userImageId.ToBson()));
var contentType = stream.FileInfo.Metadata["ContentType"].AsString;
//File(stream, contentType);
IFormFile file = new FormFile(stream, 0, stream.Length,"","");
var UserImgBinder = new UserImgBinder
{
User = _context.User.Where(x => x.UserId.Equals(id)).FirstOrDefault(),
ImageUpload = file
};
return View(UserImgBinder);
}
}
Since ImageUpload is of type List and what I am trying to feed it is not a list I am getting error.
What should I write to solve this? Is this approach bad?
Please help.
Thanks.
Try code like:
var UserImgBinder = new UserImgBinder
{
User = _context.User.Where(x => x.UserId.Equals(id)).FirstOrDefault(),
ImageUpload = new List<IFormFile> {
file
}
};
I have certain page having both long (Page1/Page2/MyPage) and simple (MyPage) addresses.
Then I want to reference it in certain place via PropertyUrl:
[CultureSpecific]
[Required]
[BackingType(typeof(PropertyUrl))]
[Display(
Name = "Link",
Description = "Link to the page",
GroupName = SystemTabNames.Content,
Order = 1)]
public virtual Url Link { get; set; }
I want the simple address (if it exists) to be used for the routing or url rendering but not the long one.
I am looking for some elegant solution for it if it exists
Got an answer from Brad McDavid
Modified it a bit to fit better to my task:
public static string GetExternalUrl(this Url url)
{
var content = UrlResolver.Service.Route(new UrlBuilder(url));
return GetExternalUrl(content);
}
public static string GetExternalUrl(this ContentReference contentReference)
{
if (ContentReference.IsNullOrEmpty(contentReference)) return null;
var content = ServiceLocator.Current.GetInstance<IContentLoader>().Get<IContent>(contentReference);
return GetExternalUrl(content);
}
public static string GetExternalUrl(this IContent content)
{
var externalProperty = content?.Property["PageExternalURL"];
return !string.IsNullOrWhiteSpace(externalProperty?.ToString()) ? $"/{externalProperty.ToString().Trim('/')}/" : null;
}
Not sure how to word this...
I have a Model, here is a section of it:
public class AnswerSheet
{
public string Q1 { get; set; }
public string Q2 { get; set; }
public string Q3 { get; set; }
public string Q4 { get; set; }
I am using a Viewmodel to reuse the same view to answer each question separately. It is almost working. Is there any way I can use my controller as follows to dynamically assign the model.q#, ex:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateNextQ([Bind(Include = "ID, qCounter, Question,Comment")] AnswerSheetCreateVM answerVM)
{
if (ModelState.IsValid)
{
string questionAns = answerVM.Question + answerVM.Comment;
AnswerSheet answer= db.AnswerSheets.Find(answerVM.ID);
//THIS PART HERE IS WHERE I HAVE A PROBLEM
answer.Q(answerVM.qCounter) = questionAns;
//That one line above
db.AnswerSheets.Add(answer);
db.SaveChanges();
So basically can I get data from my controller variable (qCounter in this case) and assign it to my model like Model.Q(qcounter)
As a side note I am open to suggestion on how to word this question or what tags to assign to it.
I found this post useful:
Set object property using reflection
This is what I ended up doing, still have to test performance:
string test = string.Format("Q" + answerVM.qCounter);
string questionAns = (answerVM.Question + " - " + answerVM.NoComment);
AnswerSheet answer= db.AnswerSheets.Find(answerVM.ID);
if (answer== null)
{
return HttpNotFound();
}
answer.GetType().GetProperty(test).SetValue(answer, questionAns, null);
db.Entry(answer).State = EntityState.Modified;
db.SaveChanges();
Maybe that will help someone down the line....NOt sure if this counts as using reflection....
I am trying to solve uri address converting to image issue. Main idea , what I am doing I want to pick image from a gallery, bind it and save it to database. Everything is working, I can save string image path to class property, but unfortunately I can't convert that address to my imageSource where I will displaying my image, because now I see empty image circle.
This is where I am selecting image from gallery and trying to convert into image:
IGalleryImageService galleryService = Xamarin.Forms.DependencyService.Get<IGalleryImageService>();
galleryService.ImageSelected += (o, imageSourceEventArgs) =>
{
Uri uri = new Uri(imageSourceEventArgs.ImageSource);
(ActivePage.Page as PageTemplate).CarImage.Source = ImageSource.FromFile(uri.ToString());
ActivePage.CarImageBindable = (ActivePage.Page as PageTemplate).CarImage.Source.GetValue(StreamImageSource.StreamProperty).ToString(); // here I am trying to convert from path address to image
};
galleryService.SelectImage();
Here is my PageTemplate
public partial class PageTemplate: ContentPage
{
public CircleImage CarImage
{
get
{
return Car;
}
set
{
Car = value;
}
}
}
and PageTemplate.xaml where I am displaying images.
<controls:CircleImage x:Name="Car" AbsoluteLayout.LayoutBounds=".5,0,-1,-1" AbsoluteLayout.LayoutFlags="PositionProportional" Aspect="AspectFill">
</controls:CircleImage>
This is my bindable property from Unit2 class:
public string CarImageBindable
{
get
{
return base.CarImage;
}
set
{
base.CarImage = value;
OnPropertyChanged(nameof(CarImageBindable));
}
}
And another property from Core project Unit class:
public int Id { get; set; }
public DateTime StartDate { get; set; }
public string CarImage { get; set; }
That's why I decided to make all properties as string data type, because I want to save image path. And yes, then convert again from database to physical image.
Thank you for answers or suggestions.
Well, I solved issue like this:
IGalleryImageService galleryService = Xamarin.Forms.DependencyService.Get<IGalleryImageService>();
galleryService.ImageSelected += (o, imageSourceEventArgs) =>
{
ActiveParking.CarImageBindable = imageSourceEventArgs.ImageSource.ToString();
(ActiveParking.Page as PageTemplate).CarImage.Source = galleryService.GetImage(imageSourceEventArgs.ImageSource.ToString());
};
galleryService.SelectImage();
I have tried so many combinations, but cannot get the validation to turn off on this code block
[ValidateInput(false)]
public ActionResult aSavePageCopy()
{
aLoggedIn();
int id = Convert.ToInt32(Request.Form["id"]);
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == id);
p.PageCopy = Request.Form["PageCopy"];
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
It seems that this works for others so I don't see what I'm missing here. The error I get is A potentially dangerous Request.Form value was detected from the client
You could use FormCollection which is safe to access instead of Request.Form (but please don't use it, see below for the real solution to your problem):
[ValidateInput(false)]
public ActionResult aSavePageCopy(FormCollection fc)
{
aLoggedIn();
int id = Convert.ToInt32(fc["id"]);
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == id);
p.PageCopy = fc["PageCopy"];
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
Of course that's an absolutely ridiculous and lousy way to solve the problem. The correct way to do it is to use a view model (of course):
public class MyViewModel
{
public int Id { get; set; }
public string PageCopy { get; set; }
}
and then:
[ValidateInput(false)]
public ActionResult aSavePageCopy(MyViewModel model)
{
aLoggedIn();
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == model.Id);
p.PageCopy = model.PageCopy;
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
or if you are using ASP.NET MVC 3 and wanted to disable validation only for a single property on your view model instead of doing it for the entire request you could decorate this view model property with the [AllowHtml] attribute:
public class MyViewModel
{
public int Id { get; set; }
[AllowHtml]
public string PageCopy { get; set; }
}
and then you no longer need the [ValidateInput(false)] attribute on your action:
public ActionResult aSavePageCopy(MyViewModel model)
{
aLoggedIn();
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == model.Id);
p.PageCopy = model.PageCopy;
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
Not only that we have solved the problem but as you can see you no longer need to write any plumbing code in your controller action parsing around integers and stuff which is the role of the model binder.