iSeller Commerce
iSeller POS Retail
iSeller POS F&B
iSeller POS Express
Crosslight
WebUI
ClientUI
What's New
Download Trial
Web Solution
Mobile Solution
Enterprise Solution
Custom Development
Blog
Community
Latest Development Blogs
ForumPostTopic
Browse By Tag
Hi,
How are images being sent via EntityContextProvider? Based on the MyInventory_WebApi sample, there are four (4) properties added to a partial class that extends the Item within the core project for the mobile platforms. Two of these properties contain the actual data of type byte[] and two are string properties resolving the Url for large and thumbnail image files. We've implemented the same set of properties in order to add/edit/delete an image for a selected record via form editor; however, the image files are not being saved on the disk. Although, the image path is being saved on the database the byte[] data for the LargeImage and ThumbnailImage properties are not being sent to the server. We've confirmed this by debugging the partial class for the Web Api Controller, and noticed that the EntityContextProvider.Files collection is null.
That being the case, please note that the Image we're trying to modify is coming from a related entity and NOT from the Item itself. Here's a code snippet to show you how things are being done from the core. The following codes assigns the new file name for the Photo, while ThumbnailImage and LargeImage contain the sets of byte[]. While the file name is being saved to the database successfully, the contents of the byte[] are not being sent to the server.
this.Item.Details.Photo = Guid.NewGuid().ToString("n") + ".jpg"; this.Item.Details.ThumbnailImage = imagePicker.Result.ThumbnailImageData; this.Item.Details.LargeImage = imagePicker.Result.ImageData;
We even tried creating the resolving properties on the same class with that of the Item, resulting to the code below, but still not working.
this.Item.Details.Photo = Guid.NewGuid().ToString("n") + ".jpg"; this.Item.ThumbnailImage = imagePicker.Result.ThumbnailImageData; this.Item.LargeImage = imagePicker.Result.ImageData;
Is there anything else we need to do here, aside from creating just the properties and assigning the results? Please advise.
Hi Jimmy,Did you already Allow Multiparts Media inside your Entity Data Model's Intersoft WebAPI EDM, if not please try changing the allow multiparts media to yes like in the screenshot.Hope that solve the problem :)Best Regard,Arief
Hi Jimmy,I made a sample and i'm successfully upload image to File, you should check it out. I also use similar structure of your model and i also already try it in IOS and Android.Here is the link sorry for using mediafire: http://www.mediafire.com/download/nnks8ymrn924djj/MyInventory_WebApi.zipI only change these files:myinventory.core\domainmodels\item.csMyInventory.Core\ViewModels\ItemEditorViewModel.csmyinventory.core\models\item.formmetadata.csmyinventory.core\bindingproviders\itemdetailbindingprovider.csMy samples based on MyInventoryAPIBased from what i found, previously i can't upload image which return error with HTML code then I use multiparts which solve the error but other than that i can upload file successfully (file appear in my webAPI folder and saved in database).I suspect maybe there are something wrong with your EDMX configurationsIf you may please send us your samplesBest Regards,Arief
Also i forgot to tell you need also changes in ItemRepository.cs:
protected override void InitializeSaveRequest(RestRequest request, IEnumerable<IEntity> entities) { var items = entities.OfType<Item>(); // send the new images (both thumbnail and large) along with the save request foreach (var item in items) { var originalItem = this.GetSingle(item.ItemID); if (originalItem.ImageDetail.ThumbnailImage != null) request.AddFile("Thumbnail", originalItem.ImageDetail.ThumbnailImage, item.Image, "image/jpg"); if (originalItem.ImageDetail.LargeImage != null) request.AddFile("Large", originalItem.ImageDetail.LargeImage, item.Image, "image/jpg"); } }
Which is rather crucial for image uploading
Okay, so here's what we did... we extended the auto-generated repository using a partial class and have overriden the InitializeSaveRequest. However, the InitializeSaveRequest method skips the call on foreach loop on save but the data is being saved. Except of course for the image files.
public class TicketMachineEditViewModel : DataEditorViewModelBase<TicketMachine, ITicketMachineRepository>
Below is the extended repository:
public partial class TicketMachineRepository { protected override void InitializeSaveRequest(RestRequest request, IEnumerable<IEntity> entities) { var p_Items = entities.OfType<TicketMachine>(); foreach (var p_Item in p_Items) { var p_OriginalItem = this.GetSingle(p_Item.TicketMachineId); var p_Machine = p_OriginalItem.Machine.MachineDetails; if (p_Machine.ThumbnailImage != null) request.AddFile("Thumbnail", p_Machine.ThumbnailImage, p_Machine.Photo, "image/jpg"); if (p_Machine.LargeImage != null) request.AddFile("Large", p_Machine.LargeImage, p_Machine.Photo, "image/jpg"); } } }
Please review and see if there's something missing. Both controller and repository files were generated using Intersoft Web API EDM Extensions.
Hi Jimmy,You actually need to call the method but it is actually useable because already generated by EDMX to inherit the EditableEntityRepository in the repository (if you peek this you can see InitializeSaveRequest). So the bottom line is, it is built-in but user can choose whether want to use it or not.Based from what i know repository generated from EDMX shouldn't expected to be changed, especially if you change the EDMX properties which means it can change repository dynamically and remove change that you made in that repository, so it is better to extend repository. I think it is also true for each files autogenerated from edmx.Did it show any error code when you save the data? I think your extended repository already right.
You also need to extend from DomainModels\InventoryModel.Controller.cs generated from edmx into web.API controller using this code:
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Web;using MyInventory.DomainModels;namespace MyInventory.DomainModels.Controllers { partial class InventoryController { public InventoryController() { db.AfterSaveChangesDelegate = (context, affectedRows) => { if (affectedRows > 0) { string imagePath = HttpContext.Current.Server.MapPath("~/images"); if (db.Files != null && db.Files.Count() > 0) { foreach (var file in db.Files) { file.Save(Path.Combine(imagePath, file.Name == "Thumbnail" ? "thumbs" : "large")); } } } }; } } }
This code is for saving the file into webHope that solve the problems :)Best RegardsArief
Hi Arief,
Yes, we've already extended the auto-generated contoller to pick-up files from DbContext on AfterChangesDelegate. But, as I have mentioned... the db.Files property is null, even with implementation of an extended repository (as posted above). As frustating as this can be, we might be dealing with something that has not been fully implemented. If we go back to the original post, the image that we are trying to update is from a related entity (e.g. this.Item.Details.Photo). When capturing the image data from this.Item.Details.ThumbnailImage and this.Item.Details.LargeImage, the properties always return null when it's inside the foreach loop. Another issue, based on related entities, if you only modify the image from the related entity (e.g. this.Item.Details.Photo)... and did not make any changes on this.Item it will never reach the loop because the entities.OfType<Item>() returns null.
Have you tested this type of scenarios? The MyInventory sample, although worth looking into... it is quite basic and the Item entity only contains a flat table implementation, wherein the fields you need is under one table. Except of course, its category. So, if you can provide a sample that deals with complex navigation or related entities, we would very much appreciate it. Although, we can always create a workaround with saving the images using a different controller with the help of RestClient, we're very anxious to see how it should be properly implemented and that if it's actually supported at all.
Many thanks!
Hi Jimmy,Sorry for late response,I see, i will try to create related entities in edmx, also can i see your models .cs file. My plan is i will create new entities name imagedetail and connected to the item, the byte will be in the imagedetailAlso could you (its ok if you couldn't) temporarily add this to your project: http://git.intersoftpt.com/projects/CROS/repos/frameworks/browse/Intersoft.AppFramework then:
Okay, considering there is a chance this.Item will not be modified but one of its related entities (e.g. this.Item.Details). In this scenario, the entities.OfType<Item>() will return null. Which means it will not enter the foreach loop, in return any chance of getting the original data from related entities is not possible. You can add the LargeImage and ThumbnailImage properties to this.Item, but these properties are useless if there aren't any changes to the entity fields. Using entities.OfType<Details>() will not return null; however, you can't use this with this.GetSingle(IEntity item) to get the original data, because the method is tied to the parent entity, which is this.Item.
Hi JimmySorry for the late respond, currently i still investigating this issue i will give you update regarding this issue, in the mean time i guess you should use your own workaround, sorry.Best Regards,Arief
Hi Jimmy,Sorry for super late response, there is actually 2 solutions for your cases, i will also explain the reasoning behind the problems.Solutions 1:if using entities.OfType<Item>() You can still use that but we need to add this inside your :
this.Item.Details.Photo = Guid.NewGuid().ToString("n") + ".jpg";
this.Item.Details.ThumbnailImage = imagePicker.Result.ThumbnailImageData;
this.Item.Details.LargeImage = imagePicker.Result.ImageData;
//Add this
this.Item.EntityAspect.EntityState = EntityState.Modified;
When you use details it actually only send what changed so only details that sent, and because what you send in the form of details it doesn't accepted in entities of type<Item>, so in my solutions i make them send both items (by set it state modified) and details using entity state Solutions 2:if using entities.OfType<Details>() You actually can use get single inside your intialize save request but you need Inject Repository/Entity that you want for example you want GetSingle from MachineDetails just add this:
private IMachineDetailsRepository MachineDetailsRepository { get { if (Container.Current.CanResolve<IMachineDetailsRepository>()) return Container.Current.Resolve<IMachineDetailsRepository>(); else return new MachineDetailsRepository(null); // design time support } }
then you can use it inside you IntializeSaveRequest:
public partial class TicketMachineRepository { protected override void InitializeSaveRequest(RestRequest request, IEnumerable<IEntity> entities) { var p_Items = entities.OfType<MachineDetails>(); foreach (var p_Item in p_Items) { var p_OriginalItem = MachineDetailRepository.GetSingle(p_Item.TicketMachineId); var p_Machine = p_OriginalItem.Machine.MachineDetails; if (p_Machine.ThumbnailImage != null) request.AddFile("Thumbnail", p_Machine.ThumbnailImage, p_Machine.Photo, "image/jpg"); if (p_Machine.LargeImage != null) request.AddFile("Large", p_Machine.LargeImage, p_Machine.Photo, "image/jpg"); } } }
Yep the getSingle actually obtained from parent entity e.g. TicketMachineRepository but you can actually inject the repository using code above so you can obtain GetSIngle from other entity, GetSIngle is function from repository (EntityRepository).
Hope that helps and sorry again this take a long time to be solvedBest RegardsArief
or
Choose this if you're already a member of Intersoft Community Forum. You can link your OpenID account to your existing Intersoft Social ID.
Choose this if you don't have an Intersoft account yet. Your authenticated OpenID will be automatically linked to your new Intersoft account.
Enter your Wordpress Blogname