Show images stored in mysql database + ASP.NET MVC - asp.net

I want to show the images stored in my database in my View.
I have a field "deliverable_image" from the type "longblob" in my mysql database.
In my controller:
public ActionResult Show( int id )
{
var imageData = repository.GetAllImages();
return File( imageData, "image/jpg" );
}
Repository:
public IQueryable<byte[]> GetAllImages()
{
return from deliverable in entities.deliverables
orderby deliverable.deliverable_image
select deliverable.deliverable_image;
}
View:
<img src='<%= Url.Action( "Show", "Deliverable", new { id = ViewData["DeliverableID"] } ) %>' />
But in my controller I get the error:
cannot convert from 'System.Linq.IQueryable' to 'string'
Does anybody knows how I can fix this?

In your action method, the very first line gets a collection of images (specifically, an IQueryable<byte[]>:
var imageData = repository.GetAllImages();
Then you try to send all of the images as a single file:
return File(imageData, "image/jpg");
imageData is a collection of files. You need to select one of them and return just that. To do that, you'll probably need to modify your GetAllImages function or use a different function. The action method is being passed an id, but you can't use that on the results of that function because all you have are byte arrays. You need to filter for the id specified and then use the resulting byte array.

Related

Web service send id to another source and return information

So I am kind of new to Web services, and I am trying to wrap my head around how it works.
Basically, I need to receive an ID from one side, pass it to another source which returns the employee information.
Now, this is what I did so far:
[WebMethod(Description = "Returns employee object for id")]
public Employee GetEmployeeById(int Id)
{
// how to ?
return new Employee( // data from outer source);
}
I see the wsdl, where you can send the id to the function.
How does the other source get the information from my service?
The another source means that anywhere you want to connect to. Maybe it's a database, other web service, or only a text file....
For example, you have a db that saves employee data. You can use Entity Framework to get employee data from db.
Like this:
[WebMethod(Description = "Returns employee object for id")]
public Employee GetEmployeeById(int Id)
{
using(var context = new MyDbContext())
{
var emp = context.Employees.Where(x => x.Id == Id).FirstOrDefault();
return emp;
}
}

Editing details on a page with a picture

I have a page with a picture and few other fields . Uploading picture works fine.If user wants to edit and put a different picture, that works fine too. The problem occurs when user edit a different field (other than the image field) in the record . After saving , the image disappears.
Here is my controller
public ActionResult Edit([Bind(Include = "GlobalMaterialId,Length,Picture")] MetalStock metalStock, HttpPostedFileBase ImageFile)
{
if (ModelState.IsValid)
{
if (ImageFile != null)
{
string pic = System.IO.Path.GetFileName(ImageFile.FileName);
metalStock.ImagePath = pic;
using (MemoryStream ms = new MemoryStream())
{
ImageFile.InputStream.CopyTo(ms);
metalStock.Picture = ms.GetBuffer();
}
}
m_db.Entry(metalStock).State = EntityState.Modified;
m_db.SaveChanges();
return RedirectToAction("Index");
}
return View(metalStock);
}
here is the image uploading bit of the view
<input name="ImageFile" type='file' / >
I understand that when I edit a field and save, ImageFile that is passed to the controller is empty and that creates the problem. I tried few other things such as trying to get the picture from the record and reassigning it to the object etc. Non of them worked. Please help.
I would guess your controller dies because it looks for a HttpPostedFile and does not get one.
You can either make it nullable in the declaration of your action
public ActionResult Edit([Bind(Include = "GlobalMaterialId,Length,Picture")] MetalStock metalStock, HttpPostedFileBase ImageFile = null)
or don't declare it in the controller at all and pick it up from the Request:
var Image = Request.Files["ImageFile"]
You could store your existing image file in a hidden field as a base64 string and in your post action check to see if the HttpPostedFileBase is null (they haven't selected a different image). If it is, convert your base64 string back to a byte array and assign it to your metalStock.Picture property.
This is how I've handled this scenario in the past. You will need to create another property on your viewmodel to hold this base64 string. This is beneficial assuming your view is not bound directly to your entity, but a viewmodel instead.

Using a custom method in LINQ to Entities

I have a LINQ expression:
var users = db.Relationships.Where(i => i.RelationshipId== relId)
.Select(s => s.User).Distinct().Select(s => new UserViewModel() {
Username = s.Username,
LastActiveDateTime = s.LastActive, // DateTime, I want it to be a string filtered through my custom GetFriendlyDate method
}).ToList();
// convert all DateTimes - yuck!
foreach (var userViewModel in users) {
userViewModel.LastActive = DateFriendly.GetFriendlyDate(userViewModel.LastActiveDateTime);
}
This solution is working, but it feels wrong to
have to iterate over all users after getting them from the db, just to reformat a property on every single one
have a DateTime property on my ViewModel just so that it can later be converted to a string and never touched again
Is there any way I can use the GetFriendlyDate method directly within the query?
Possible solutions, worth to mention:
Have a getter property of your ViewModel, which would return transformed string, something like:
public string LastActive
{
get
{
return DateFriendly.GetFriendlyDate(LastActiveDateTime);
}
}
Though it not solves your problem with existing LastActiveDateTime column, transformation will be applied only at moment of usage (in your view, most likely - anyways if you will try use it somewhere latter in query, it will not work for reason you already know), so no need to iterate manually.
Create View, which will transform data on server side; so your data will already be returned in format you need, if you're using DBFirst, probably, it's easiest and fastest solution;
Finally, you can use ToList() twice, once before selecting new ViewModel() (or call AsEnumerable(), or find other way to materialize query). It will fetch data from database and will allow you perform any C#-side functions you want directly in query after ToList(). But, as mentioned before - it's about getting all data, which matched criteria up to ToList() - in most cases it's not appropriate solution.
And here is some additional readings:
How can I call local method in Linq to Entities query?
I tested it in LINQpad and it works.
It still kinda iterates over users (with LINQ) but you don't have to add DateTime property to your viewmodel class. Also you could convert collection of Users to collection of UserViewModel objects with Automapper. It would still iterate over users of course but you wouldn't see it.
Had to create some setup code of course because I don't have your database.
void Main()
{
var db = new List<User> {
new User { LastActive = DateTime.Now, Username = "Adam", Lastname = "Nowak" },
new User { LastActive = DateTime.Now.AddYears(1), Username = "Eve", Lastname = "Kowalska"}
};
// select only properties that you need from database
var users = db
.Select(user => new { Username = user.Username, LastActive = user.LastActive})
.Distinct()
.ToList();
var usersVM = from u in users
select new UserViewModel { Username = u.Username, LastActiveDateTime = DateFriendly.GetFriendlyDate(u.LastActive)};
usersVM.Dump();
}
class User
{
public DateTime LastActive;
public string Username;
public string Lastname;
};
class UserViewModel
{
public string Username;
public string LastActiveDateTime;
}
static class DateFriendly
{
public static string GetFriendlyDate(DateTime date)
{
return "friendly date " + date.Year;
}
}
And this outputs
Username LastActiveDateTime
Adam friendly date 2013
Eve friendly date 2014
There is no direct Concert.ToDate method available for LINQ. But you can try using the DateAdd method from the SqlFunctions class:
var users = db.Relationships.Where(i => i.RelationshipId== relId)
.Select(s => new
{
s.User.Username,
LastActive=SqlFunctions.DateAdd("d",0, s.LastActive)
})
.ToList().Select(s => new UserViewModel()
{
Username = s.Username,
LastActiveDateTime = s.LastActive
});
Wouldn't the following work?
var users = db.Relationships.Where(i => i.RelationshipId== relId)
.Select(s => s.User).Distinct().Select(s => new UserViewModel() {
Username = s.Username,
LastActiveDateTime = DateFriendly.GetFriendlyDate(s.LastActive)
}).ToList();

Validating a field based on a different database table / entity

I am writing an MVC 4 application, and using Entity Framework 4.1. I have a validation question which I cannot seem to find the answer to.
Essentially, I have an Entity (object) called "Product" which contains a field "Name", which must follow strict naming conventions which are defined in a separate Entity called "NamingConvention". When the user enters a value, the system needs to check it against the rules established in the NamingConvention entity, and return an error if need be.
Where should this validation be done, and how? I need to check the NamingConvention entity when doing the validation, which means I would need a database context since I'm referencing a different entity. Is there any validation method which won't require me to create a new context? I was thinking of doing the validation in the Controller, since it already creates a data context, but this doesn't seem like the right place to do it.
Thanks for any help!
I have done things like this using a JQuery post (ajax) call from the webpage where the name is being entered. You then post (the value of name) to a method on your controller which can return a JSON value that contains a flag saying if the validation passed and also a message that you want to return to your user. For example :
Javascript in webpage :
$("#name").change(function () {
var nameVal = $(this).val();
$.post(getRoot() + "/NameController/ValidateName", { name: nameVal },
function (data) {
if (data.valid == "true") {
alert("A valid name was chosen");
} else
{
alert(data.message);
}
}, "json");
});
Controller (NameController) Code :
[HttpPost]
public ActionResult ValidateName(string name)
{
// actual validation carried out in a static utility class (Utils.IsNameValid)
// if you are loading the same validation rules from your table each time
// consider caching the data in the application cache or a static List.
bool nameIsValid = Utils.IsNameValid(name, out string ErrorMessage);
JsonResult result = new JsonResult();
result.Data = new { valid = (nameIsValid "true" : "false"), message = ErrorMessage };
return result;
}
I'm using EF 5 but believe you can use this method ... apologies in advance if I'm misleading you with this answer.
You could do the validation within your context (or a context decorator)
public override int SaveChanges()
{
var products = this.GetChangedProducts();
foreach (var product in products)
{
this.ValidateName(product);
}
return base.SaveChanges();
}
private IEnumerable<Product> GetChangedProducts()
{
return (
from entry in _context.ChangeTracker.Entries()
where entry.State != EntityState.Unchanged
select entry.Entity)
.OfType<Product>();
}
private void ValidateName(Product product)
{
//validate here
}

Return IQueryable<string>

I'm using pageList (the one made by troy goode), on his example he has
// in this case we return IEnumerable<string>, but in most
// - DB situations you'll want to return IQueryable<string>
private IEnumerable<string> GetStuffFromDatabase()
{
var sampleData = new StreamReader(Server.MapPath("~/App_Data/Names.txt")).ReadToEnd();
return sampleData.Split('\n');
}
Since i'm using a database i changed to IQueryable, but, i don't know what to write inside to return the data from the database, i tried changing the path to ~/App_Data/DatabaseName.sdf but i get that sampleData.Split('\n');
cannot implicitly convert type string to system.linq.iqueryable<string>
How i can change that?
return sampleData.Split('\n').AsQueryable();
The return type of your method is IEnumerable and requires to return as Enumeration
so please do this way
return sampleData.Split('\n').AsEnumerable();

Resources