nhibernate query select specific colmns including IList - sql

Ive got a problem with selecting specyfic columns (properties), code below:
Entities:
public class Item {
public Item() {
Images = new List<Image>();
}
public virtual int Id { get; set; }
public virtual int ItemNum { get; set; }
public virtual Channel Channel { get; set; }
public virtual string Title { get; set; }
public virtual string Comment { get; set; }
public virtual string Text { get; set; }
public virtual string Link { get; set; }
public virtual string Category { get; set; }
public virtual DateTime? PublishDate { get; set; }
public virtual string ExternalId { get; set; }
public virtual string SourceImage { get; set; }
public virtual string Bubble { get; set; }
public virtual IEnumerable<Image> Images { get; set; }
}
public class Image {
public Image() { }
private string type;
public virtual int Id { get; set; }
public virtual bool IsMobile { get; set; }
public virtual Item Item { get; set; }
public virtual string Type {get;set;}
public virtual string ImageUrl { get; set; }
public virtual int? Height { get; set; }
public virtual int? Width { get; set; }
public virtual int? ImgXOff { get; set; }
public virtual int? ImgYOff { get; set; }
public virtual decimal? ImgZoom { get; set; }
}
And now I would like to get only Item.Id and all related to row with this Id, my query
var minDate = DateTime.Today - TimeSpan.FromDays(config.ItemsFromLastDaysCount);
var items = session.Query<Item>()
.Fetch(x => x.Channel)
.Where(x => x.Channel.InsertionDate >= minDate)
.OrderByDescending(x => x.Channel.InsertionDate)
.Take(config.ItemsOnOnePage)
.Select(x => new
{
Id = x.Id,
Images = x.Images
}).ToList();
But query like this throws strange to me exception:
"An exception of type 'System.ArgumentException' occurred in System.Core.dll but was not handled in user code
Additional information: Expression of type 'System.Collections.IList' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable`1[System.Object]'"
Stack trace:
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
at System.Linq.Expressions.Expression.Invoke(Expression expression, IEnumerable`1 arguments)
at System.Linq.Expressions.Expression.Invoke(Expression expression, Expression[] arguments)
at NHibernate.Linq.ExpressionToHqlTranslationResults.MergeLambdasAndCompile(IList`1 transformations)
at NHibernate.Linq.ExpressionToHqlTranslationResults..ctor(HqlTreeNode statement, IList`1 itemTransformers, IList`1 listTransformers, IList`1 postExecuteTransformers, List`1 additionalCriteria)
at NHibernate.Linq.IntermediateHqlTree.GetTranslation()
at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at TicTac.Service.Controllers.HomeController.Index() in d:\Projekty\Hypermedia\TicTac.RssReader\branches\TicTac.RssReader\TicTac.Service\Controllers\HomeController.cs:line 27
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
exception is because of line:
Images = x.Images
I will be very greatefull for response.

Related

Missing Map from 'Object' to 'Object' when using ProjectTo<>

I am working on Web API and have mappings to convert from Domain models to Application models using AutoMapper(10.1.1)
I have registered AutoMapper in Application layer
public static IServiceCollection ConfigureAppServices(this IServiceCollection services)
{
services.AddAutoMapper(Assembly.GetExecutingAssembly());
services.AddMediatR(Assembly.GetExecutingAssembly());
//services.AddMvc().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<StartUp>())
// services.AddControllersWithViews();
return services;
}
Used this class in Web API startup.cs
services.ConfigureAppServices();
I have this generic interface for Mapping called IMapFrom
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
Mapping is from 'JobModel' to 'JobDetailsDto'
public class JobDetailsDto: IMapFrom<JobModel>
{
public JobDetailsDto()
{
}
public string Id { get; set; }
public string Name { get; set; }
public string JobType { get; set; }
public string ShipBranch { get; set; }
public string ProjectManager { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<JobModel, JobDetailsDto>()
.ForMember(d => d.ShipBranch, opt => opt.MapFrom(s => s.PriceBranch))
.ForMember(d => d.ProjectManager, opt => opt.MapFrom(s => s.BidderId));
}
}
JobModel.cs
public class JobModel
{
public JobModel()
{
}
public int Id { get; set; }
public DateTime BidDate { get; set; }
public string JobType { get; set; }
public DateTime CreatedDate { get; set; }
public string City { get; set; }
public string State { get; set; }
public string BidderId { get; set; }
public string PriceBranch { get; set; }
public string Name { get; set; }
}
I am using MediaTr to handle API requests
public async Task<JobDetailsDto> Handle(GetJobDetailsQuery request, CancellationToken cancellationToken)
{
var vm = await _context.JobModels
.Where(e => e.Id == request.Id)
.ProjectTo<JobDetailsDto>(_mapper.ConfigurationProvider)
.SingleOrDefaultAsync(cancellationToken);
return vm;
}
When I perform 'GET' which fetches data in 'JobModel' object and converts to 'JobDetailsDto' throws below error
System.InvalidOperationException: Missing map from Domain.Entities.JobModel to Application.ApplicationBusiness.Job.Queries.JobDetailsDto. Create using CreateMap<JobModel, JobDetailsDto>.
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary2 typePairCount, LetPropertyMaps letPropertyMaps, TypeMap& typeMap) at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request, IDictionary2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request)
at AutoMapper.Internal.LockingConcurrentDictionary2.<>c__DisplayClass2_1.<.ctor>b__1() at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy1.CreateValue()
at System.Lazy1.get_Value() at AutoMapper.Internal.LockingConcurrentDictionary2.GetOrAdd(TKey key)
at AutoMapper.QueryableExtensions.ExpressionBuilder.GetMapExpression(Type sourceType, Type destinationType, Object parameters, MemberInfo[] membersToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore(Type destinationType, Object parameters, IEnumerable1 memberPathsToExpand) at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore[TResult](Object parameters, IEnumerable1 memberPathsToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.To[TResult](Object parameters, Expression1[] membersToExpand) at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Object parameters, Expression1[] membersToExpand)
at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Expression`1[] membersToExpand)
Try this.
public JobDetailsDto()
{
Mapping();
}
public void Mapping()
{
CreateMap<JobModel, JobDetailsDto>()
.ForMember(d => d.ShipBranch, opt => opt.MapFrom(s => s.PriceBranch))
.ForMember(d => d.ProjectManager, opt => opt.MapFrom(s => s.BidderId));
}
Another solution is instead of writing mapping inside dto, you should create MappingProfile, where you will add your Mappings. Then in your service you should add it in constructor
_mapperConfig = new MapperConfiguration(cfg => { cfg.AddProfile<MappingProfile>(); });

MVC4 AllowHtml not working with Dictionary

I have a class
public class TemplateViewModel
{
[AllowHtml]
public string Template { get; set; }
[AllowHtml]
public Dictionary<string, string> LocalizedContents { get; set; }
}
When I input html code for Template, it's fine.
When I input html code for LocalizedContents, it prompt out the error
System.Web.HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (LocalizedContents[en-us]="...ate:
FB: <a href="www.faceboo...").
at System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection)
at System.Web.HttpValueCollection.EnsureKeyValidated(String key)
at System.Web.HttpValueCollection.GetValues(String name)
at System.Web.Mvc.NameValueCollectionValueProvider.ValueProviderResultPlaceholder.GetResultFromCollection(String key, NameValueCollection collection, CultureInfo culture)
at System.Web.Mvc.NameValueCollectionValueProvider.GetValue(String key, Boolean skipValidation)
at System.Web.Mvc.ValueProviderCollection.GetValue(String key, Boolean skipValidation)
at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.DefaultModelBinder.CreateEntryForModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type valueType, IModelBinder valueBinder, String modelName, Object modelKey)
at System.Web.Mvc.DefaultModelBinder.UpdateDictionary(ControllerContext controllerContext, ModelBindingContext bindingContext, Type keyType, Type valueType)
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.DefaultModelBinder.GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
at System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
at System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model)
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
at System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState)
Any solution for the [AllowHtml] to be use for Dictionary?
I do not prefer to use the [ValidateInput(false)] as it will have security concern
I also do not want to include <httpRuntime requestValidationMode="2.0" /> in my web config
The alternative way to achieve this is to create a class for the datatype and assign the [AllowHtml] for the property of the class.
public class LocalizedContents
{
[AllowHtml]
public string Key { get; set; }
[AllowHtml]
public string Value { get; set; }
}
Then put the class as datatype for LocalizedContents property
public class TemplateViewModel
{
public string Template { get; set; }
public List<LocalizedContents> LocalizedContents { get; set; }
}

Value cannot be null when using join in OrmLite / Servicestack / Linqpad

When joining two tables I get
ArgumentNullException: Value cannot be null. Parameter name: key.
This happens after executing the query, change any line in Linqpad and execute again.
using (var db = _factory.OpenDbConnection())
{
var q = db.From<Customer>()
.Join<Customer, Address>();
var results = db.SelectMulti<Customer, Address>(q);
results.Dump();
}
Customer
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
Address
public class Address
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
ServiceStack throws this error
at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
at ServiceStack.TypeExtensions.GetActivator(ConstructorInfo ctor)
at ServiceStack.OrmLite.OrmLiteUtils.ConvertToList[T](IDataReader reader, IOrmLiteDialectProvider dialectProvider, HashSet`1 onlyFields)
at ServiceStack.OrmLite.OrmLiteResultsFilterExtensions.ExprConvertToList[T](IDbCommand dbCmd, String sql, IEnumerable`1 sqlParams, HashSet`1 onlyFields)
at ServiceStack.OrmLite.ReadExpressionCommandExtensions.SelectMulti[T,T2](IDbCommand dbCmd, SqlExpression`1 q)
at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter)
at UserQuery.Main() in C:\Users\kairu\AppData\Local\Temp\LINQPad5\_uimlqbjb\plnhhb\LINQPadQuery.cs:line 54
at LINQPad.ExecutionModel.ClrQueryRunner.Run()
at LINQPad.ExecutionModel.Server.RunQuery(QueryRunner runner)
at LINQPad.ExecutionModel.Server.StartQuery(QueryRunner runner)
at LINQPad.ExecutionModel.Server.<>c__DisplayClass153_0.<ExecuteClrQuery>b__0()
at LINQPad.ExecutionModel.Server.SingleThreadExecuter.Work()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Using ServiceStack version 5.1.0 net45
This example works as expected on Gistlyn:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Address
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
db.CreateTable<Customer>();
db.CreateTable<Address>();
db.Insert(new Customer { Id = 1, Name = "C" });
db.Insert(new Address { Id = 1, CustomerId = 1 });
var q = db.From<Customer>()
.Join<Customer,Address>();
var results = db.SelectMulti<Customer, Address>(q);
results.PrintDump();
It might be an issue with LINQ Pad.

ASP.NET Web Api System.Runtime.Serialization.SerializationException

I have a fully working MVC4 web site to which today I am trying to add a Web API though without success.
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Data.Entity.Infrastructure.DbQuery`1[[LeasingWeb.Models.Car, LeasingWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' with data contract name 'ArrayOfCar:http://schemas.datacontract.org/2004/07/LeasingWeb.Models' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at WriteCarDBToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract ) at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.<>c__DisplayClass7.<WriteToStreamAsync>b__6() at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)
</StackTrace>
</InnerException>
</Error>
My objects are these:
public class Image
{
public int ID { get; set; }
[Required(ErrorMessage="Please select a car")]
[ForeignKey("Car")]
public int CarID { get; set; }
[DisplayName("Picture")]
[Required]
[FileExtensions(ErrorMessage = "Please specify a valid image file (.jpg, .jpeg, .gif or .png)", Extensions = ("jpg,png,jpeg"))]
public string Name { get; set; }
public virtual Car Car { get; set; }
}
public class Car
{
public int ID { get; set; }
[Required]
[DisplayName("Car Model")]
public string Name { get; set; }
[Required]
public string Company { get; set; }
[Required]
[DisplayName("Car Type")]
[ForeignKey("CarType")]
public int CarTypeID { get; set; }
[Required]
[Range(1,5)]
[DisplayName("Number Of Doors")]
public float NumDoors { get; set; }
[Required]
[Range(0, Int32.MaxValue)]
public float Acceleration { get; set; }
public virtual CarType CarType { get; set; }
}
public class CarType
{
[Key]
public int ID { get; set; }
[Required]
[DataType(DataType.Text)]
public string Type { get; set; }
}
And an object that holds them both:
public class CarDB
{
public IQueryable<Car> Cars { get; set; }
public IEnumerable<Image> Images { get; set; }
}
The API Controller:
public CarDB Get(int ID = -1)
{
CarDB car = new CarDB();
if (ID == -1)
{
car = new CarDB { Cars = db.Cars.Include(c => c.CarType), Images = db.Images };
}
else
{
car = new CarDB { Cars = db.Cars.Where(c => c.ID == ID).Include(c => c.CarType), Images = db.Images.Where(c => c.CarID == ID) };
}
return car;
}
Thanks to anyone that can help.
The issue here is the Cars member on the CarDB object. The DataContractSerializer special cases collection interfaces like IEnumerable and IList, but it doesn't special case derived interfaces like IQueryable. For these interfaces, they're treated as if the type were object and any implementations must be declared as known types.
You can try fixing this by changing the IQueryable<Car> member to IEnumerable<Car>.
I had this problem with legacy code using 30 tables with about 40 Foreign Keys with Lazy Loading. I found it easier, rather than adding more annotations to all the database classes, to just create a ViewModel with the fields that I wanted to be returned.
If the data being returned is complex, then I suggest using automapper.

IEnumerable and WCF - yet again

OK... I've looked on the web and found two possible solutions to my issue of not being able to return an IEnumerable type in a .Net 4.0 WCF service.
See below link. This is exactly what I'm getting when I am executing the WCF Test Client tool and trying to invoke a method.
https://connect.microsoft.com/wcf/feedback/details/336696/ienumerable-t-serialization-bug
Mind you, to be sure there is nothing wrong with my web service, I am able to return a type of this object for a single record, just not an IEnumerable.
Both solutions that I have tried, shown below do not work for me. I get the same error. This is driving me crazy. I know what the issue is, followed steps to circumvent the issue, but I am still getting the same error.
How can I resolve this?
This is the first solution I tried: Note that I even tried removing the "ToList" and "ToArray" on the last statement in each of the methods because it's implied already.
Interface
[OperationContract]
IList<Priority> GetPriorities();
Method
public IList<Priority> GetPriorities()
{
YeagerTechEntities DbContext = new YeagerTechEntities();
IList<Priority> priority = DbContext.Priorities.Where(p => p.PriorityID > 0).ToList();
CloseConnection(DbContext);
return priority.ToList();
}
This is the second solution I tried:
Interface
[OperationContract]
Priority[] GetPriorities();
Method
public Priority[] GetPriorities()
{
YeagerTechEntities DbContext = new YeagerTechEntities();
Priority[] priority = DbContext.Priorities.Where(p => p.PriorityID > 0).ToArray();
CloseConnection(DbContext);
return priority.ToArray();
}
Here it is with a List instead of an IList which still doesn't work.
Interface
[OperationContract]
List<Priority> GetPriorities();
Method
public List<Priority> GetPriorities()
{
YeagerTechEntities DbContext = new YeagerTechEntities();
List<Priority> priority = DbContext.Priorities.Where(p => p.PriorityID > 0).ToList();
CloseConnection(DbContext);
return priority.ToList();
}
Notice that the below method works fine when retrieving just one object instead of a list.
[OperationContract]
Priority GetPriorityID(Int16 priorityid);
public Priority GetPriorityID(Int16 priorityid)
{
YeagerTechEntities DbContext = new YeagerTechEntities();
Priority priority = null;
var priorityEntity = (from p in DbContext.Priorities
where p.PriorityID == priorityid
select p).FirstOrDefault();
if (priorityEntity != null)
{
priority = new Priority();
priority.PriorityID = priorityEntity.PriorityID;
priority.Description = priorityEntity.Description;
CloseConnection(DbContext);
}
else
{
CloseConnection(DbContext);
throw new Exception("Priority " + priorityid + " not found!");
}
return priority;
}
The entire error msg from the wcf test client for the first method in this post is as follows. What is the resolution in order to be able to return a list of objects?
Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.
An error occurred while receiving the HTTP response to http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ClientReliableChannelBinder1.RequestClientReliableChannelBinder1.OnRequest(TRequestChannel channel, Message message, TimeSpan timeout, MaskingMode maskingMode)
at System.ServiceModel.Channels.ClientReliableChannelBinder1.Request(Message message, TimeSpan timeout, MaskingMode maskingMode)
at System.ServiceModel.Channels.ClientReliableChannelBinder1.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionClientSettings`1.SecurityRequestSessionChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at IYeagerTechWcfService.GetPriorities()
at YeagerTechWcfServiceClient.GetPriorities()
Inner Exception:
The underlying connection was closed: An unexpected error occurred on a receive.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
Inner Exception:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)
Inner Exception:
An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
I modified my classes (see below), but am still getting the same exact error.
Surely, there must be someone who has tried this before where they get an object back from Entity Framework and want to pass it back as an IEnumerable. I'm very frustrated with this. Please help me out...
Based on my previous post, my classes are exactly the same with the following changes. I tried two methodologies.
Please refer to the first and second scenarios separately.
First scenario for Interface
I tried using just the Customer class and then an IEnumerable declaration of it.
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using YeagerTechModel;
namespace YeagerTechWcfService
{
//[ServiceKnownType(typeof(YeagerTechModel.Customer))]
[ServiceKnownType(typeof(IEnumerable<YeagerTechModel.Customer>))]
[ServiceContract]
public interface IYeagerTechWcfService
{
[OperationContract]
IEnumerable<Customer> GetCustomers();
[OperationContract]
Customer GetCustomerID(Int16 customerid);
It resides in my YeagerTechModel project in the same solution referenced by my web service (the other project in the same solution).
First scenario for Customer object
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace YeagerTechModel
{
[Serializable]
[DataContract]
public partial class Customer
{
public Customer()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CustomerID { get; set; }
[Required]
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string Email { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Company { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string FirstName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string LastName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address1 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address2 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string City { get; set; }
[StringLength(2)]
[DataType(DataType.Text)]
[DataMember]
public string State { get; set; }
[StringLength(10)]
[DataType(DataType.Text)]
[RegularExpression(#"^\d{5}(-\d{4})?$")]
[DataMember]
public string Zip { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
public string HomePhone { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[DataMember]
public string CellPhone { get; set; }
[StringLength(100)]
[DataType(DataType.Url)]
[DataMember]
public string Website { get; set; }
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string IMAddress { get; set; }
[DataMember]
public System.DateTime CreatedDate { get; set; }
[DataMember]
public Nullable<System.DateTime> UpdatedDate { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
Second scenario for interface:
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using YeagerTechModel;
namespace YeagerTechWcfService
{
[ServiceContract]
public interface IYeagerTechWcfService
{
[OperationContract]
IEnumerable<Customer> GetCustomers();
[OperationContract]
Customer GetCustomerID(Int16 customerid);
Second scenario for Customer object
I have tried using just the Customer class and then an IEnumerable declaration of it at the bottom of this class.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace YeagerTechModel
{
[KnownTypeAttribute("KnownTypes")]
[Serializable]
[DataContract]
public partial class Customer
{
public Customer()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CustomerID { get; set; }
[Required]
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string Email { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Company { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string FirstName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string LastName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address1 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address2 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string City { get; set; }
[StringLength(2)]
[DataType(DataType.Text)]
[DataMember]
public string State { get; set; }
[StringLength(10)]
[DataType(DataType.Text)]
[RegularExpression(#"^\d{5}(-\d{4})?$")]
[DataMember]
public string Zip { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
public string HomePhone { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[DataMember]
public string CellPhone { get; set; }
[StringLength(100)]
[DataType(DataType.Url)]
[DataMember]
public string Website { get; set; }
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string IMAddress { get; set; }
[DataMember]
public System.DateTime CreatedDate { get; set; }
[DataMember]
public Nullable<System.DateTime> UpdatedDate { get; set; }
public virtual ICollection<Project> Projects { get; set; }
static Type[] KnownTypes()
{
return new Type[] { typeof(IEnumerable<Customer>) };
}
}
I tried:
return customer;
return customer.ToList();
return customer.ToArray();
public IEnumerable<Customer> GetCustomers()
{
YeagerTechEntities DbContext = new YeagerTechEntities();
IEnumerable<Customer> customer = DbContext.Customers.Where(p => p.CustomerID > 0);
CloseConnection(DbContext);
return customer;
}
The problem seems to be a serialization issue when trying to pass back the Customer object which is part of an Entity Framework model. There has to be a documented way of passing back an object of this type which is derived from an Entity Framework model.
Where is it????
Here is the latest of what I tried and am still getting the same exact error....
namespace YeagerTechWcfService
{
[ServiceContract]
public interface IYeagerTechWcfService
{
[OperationContract]
List<Customer> GetCustomers();
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace YeagerTechModel
{
[Serializable]
[DataContract]
public partial class Customer
{
public Customer()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CustomerID { get; set; }
[Required]
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string Email { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Company { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string FirstName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string LastName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address1 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address2 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string City { get; set; }
[StringLength(2)]
[DataType(DataType.Text)]
[DataMember]
public string State { get; set; }
[StringLength(10)]
[DataType(DataType.Text)]
[RegularExpression(#"^\d{5}(-\d{4})?$")]
[DataMember]
public string Zip { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
public string HomePhone { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[DataMember]
public string CellPhone { get; set; }
[StringLength(100)]
[DataType(DataType.Url)]
[DataMember]
public string Website { get; set; }
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string IMAddress { get; set; }
[DataMember]
public System.DateTime CreatedDate { get; set; }
[DataMember]
public Nullable<System.DateTime> UpdatedDate { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
public List<Customer> GetCustomers()
{
YeagerTechEntities DbContext = new YeagerTechEntities();
List<Customer> customer = DbContext.Customers.Where(p => p.CustomerID > 0).ToList();
return customer.ToList();
}
The answer was as simple as setting a property to false before making my EF call to the database.
DbContext.Configuration.ProxyCreationEnabled = false;
EF automatically generates a proxy class. Dynamic Proxies – They don’t play nice over the wire – Turn these off (ContextOptions.ProxyCreationEnabled == false).