using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Web;
using System.Web.Mvc;
namespace MvcMusicStore.Controllers
{
public class StoreController : Controller
{
//
// GET: /Store/
public string Index()
{
// ERROR call extension method here
return GetMemberName();
}
}
public static class Utilities
{
public static string GetMemberName(this Controller caller, [CallerMemberName] string memberName = "")
{
return caller.GetType().FullName + "." + memberName;
}
}
}
My extension method is not recognized, what is wrong?
Prefix the call with this:
public class StoreController : Controller
{
//
// GET: /Store/
public string Index()
{
return this.GetMemberName();
}
}
Related
Preface
I have created an ASP.NET Code Web API using Visual Studio 2022 to familiarise myself with the topic of "Web APIs".
I have converted the project to .NET 5.
In the MyControllers.cs I have so far code for a Get and for a Post request.
I have removed the WeatherForecast.cs created by Visual Studio. I have also set in the launchSettings.json that the browser jumps to MyController from the beginning.
To practice Dependency Injection, I added another project called TextRepository (a class library) to the assembly. I had written a text file with another Visual Studio project that contains the numbers from 0–99. This text file is read in and returned in the Get method of MyController.cs. Now the numbers are displayed in the browser when called. I had also included the interface INumberRepository.
To practise the whole thing again, I created another repository: ImageRepository. The aim is to find all pictures in the folder Pictures and store them in a List. To do this, I downloaded System.Drawing.Common from the NuGet package manager.
Question for you:
I am still struggling a bit to request the API in the browser for different purposes. I still want to use the call https://localhost:44355/api/My for displaying the numbers in the browser, i.e., the Get method. How can I make it so that I use a different link to transfer the image data? I am concerned with the call to the API – do I have to write a second Get function? – And about transferring the bytes of the images.
If anyone wonders what the images are: I have created 2 test images for this purpose (1920 pixels ×1080 pixels).
WebApplication2
in Startup.cs
services.AddScoped<TextRepository.INumberRepository, TextRepository.NumberTextFileRepository>();
services.AddScoped<ImageRepository.IImageTransferRepository, ImageRepository.ImageTransferRepository>();
MyController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using TextRepository;
using ImageRepository;
namespace WebApplication2.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private readonly INumberRepository numberRepository;
private readonly IImageTransferRepository imageRepository;
public MyController(INumberRepository numberRepository, IImageTransferRepository imageTransferRepository)
{
this.numberRepository = numberRepository;
this.imageRepository = imageTransferRepository;
}
[HttpGet]
public ActionResult<List<int>> Get()
{
List<int> numbers = this.numberRepository.GetNumbers();
List<System.Drawing.Bitmap> foundImages = this.imageRepository.GetImages();
return Ok(numbers);
}
[HttpPost]
public IActionResult Post([FromBody] DataTransferObject transferObject)
{
return Ok(transferObject.PassedString + $" {transferObject.Zahl}");
}
}
}
TextRepository
TextFileParser.cs
using System;
using System.Collections.Generic;
using System.IO;
namespace TextRepository
{
public class TextFileParser
{
public static List<int> ReadAllData(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
string[] allLines = System.IO.File.ReadAllLines(path);
if (allLines == null)
{
throw new Exception("War null");
}
if (allLines.Length < 1)
{
throw new Exception("Die Datei enthält 0 Zeilen.");
}
if (allLines.Length == 1)
{
return new List<int>();
}
List<int> numbers = new List<int>();
for (int i = 1; i < allLines.Length; i++)
{
if (int.TryParse(allLines[i], out int result))
{
numbers.Add(result);
}
else
{
Console.WriteLine($"In der Textdatei, in Zeile {i + 1}, ist eine inkorrekte Zahl aufgetreten.");
continue;
}
}
return numbers;
}
}
}
NumberTextFileRepository
using System.Collections.Generic;
namespace TextRepository
{
public class NumberTextFileRepository : INumberRepository
{
public List<int> GetNumbers()
{
System.IO.DirectoryInfo Root = new System.IO.DirectoryInfo(System.IO.Directory.GetCurrentDirectory());
return TextFileParser.ReadAllData(Root.Parent.FullName + "\\Textdatei.txt");
}
}
}
INumberRepository.cs
using System.Collections.Generic;
namespace TextRepository
{
public interface INumberRepository
{
List<int> GetNumbers();
}
}
ImageTransferRepository
ImageTransferRepository.cs
using System;
using System.Collections.Generic;
namespace ImageRepository
{
public class ImageTransferRepository : IImageTransferRepository
{
public List<System.Drawing.Bitmap> GetImages()
{
return ImageTransfer.GetImagesFromFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures));
}
}
}
ImageTransfer.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ImageRepository
{
public class ImageTransfer
{
public static List<System.Drawing.Bitmap> GetImagesFromFolder(string path)
{
if (!Directory.Exists(path))
{
throw new FileNotFoundException(path);
}
List<FileInfo> fileInfos = new List<FileInfo>();
fileInfos.AddRange(new DirectoryInfo(path).EnumerateFiles().Where(f => IsValidFile(f)));
fileInfos = fileInfos.OrderBy(x => x.CreationTime).ToList(); // The newest image should be at the top of the list.
return (from FileInfo file in fileInfos select new System.Drawing.Bitmap(file.FullName)).ToList();
}
private static bool IsValidFile(FileInfo File)
{
return File.FullName.ToLower().EndsWith(".bmp") ^ File.FullName.ToLower().EndsWith(".jpeg") ^ File.FullName.ToLower().EndsWith(".jpg") ^ File.FullName.ToLower().EndsWith(".png");
}
}
}
IImageTransferRepository.cs
using System.Collections.Generic;
using System.Drawing;
namespace ImageRepository
{
public interface IImageTransferRepository
{
List<Bitmap> GetImages();
}
}
I still want to use the call https://localhost:44355/api/My for displaying the numbers in the browser, i.e., the Get method. How can I make it so that I use a different link to transfer the image data? I am concerned with the call to the API – do I have to write a second Get function? – And about transferring the bytes of the images.
If you want to return List<int> numbers and List<System.Drawing.Bitmap> foundImages together,you can try to create a class which contains the two lists.Or you need to write a second Get function.
public class TestModel {
public List<int> numbers { get; set; }
public List<System.Drawing.Bitmap> foundImages { get; set; }
}
Get function:
[HttpGet]
public ActionResult<TestModel > Get()
{
TestModel t=new TestModel();
t.numbers = this.numberRepository.GetNumbers();
t.foundImages = this.imageRepository.GetImages();
return Ok(t);
}
If you want to create a second Get function,here is the demo:
[HttpGet]
public ActionResult<List<int>> Get()
{
List<int> numbers = this.numberRepository.GetNumbers();
return Ok(numbers);
}
[HttpGet("foundImages")]//route will be https://localhost:44355/api/My/foundImages
public ActionResult<List<System.Drawing.Bitmap>> Get()
{
List<System.Drawing.Bitmap> foundImages = this.imageRepository.GetImages();
return Ok(foundImages);
}
I wish to alias the name of my request object properties, so that these requests both work and both go to the same controller:
myapi/cars?colors=red&colors=blue&colors=green and myapi/cars?c=red&c=blue&c=green
for request object:
public class CarRequest {
Colors string[] { get; set; }
}
Has anyone been able to use the new ModelBinders to solve this without having to write ModelBindings from scratch?
Here is a similar problem for an older version of asp.net and also here
I wrote a model binder to do this:
EDIT:
Here's the repo on github. There are two nuget packages you can add to your code that solve this problem. Details in the readme
It basically takes the place of the ComplexTypeModelBinder (I'm too cowardly to replace it, but I slot it in front with identical criteria), except that it tries to use my new attribute to expand the fields it's looking for.
Binder:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MYDOMAIN.Client;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
namespace MYDOMAIN.Web.AliasModelBinder
{
public class AliasModelBinder : ComplexTypeModelBinder
{
public AliasModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory,
bool allowValidatingTopLevelNodes)
: base(propertyBinders, loggerFactory, allowValidatingTopLevelNodes)
{
}
protected override Task BindProperty(ModelBindingContext bindingContext)
{
var containerType = bindingContext.ModelMetadata.ContainerType;
if (containerType != null)
{
var propertyType = containerType.GetProperty(bindingContext.ModelMetadata.PropertyName);
var attributes = propertyType.GetCustomAttributes(true);
var aliasAttributes = attributes.OfType<BindingAliasAttribute>().ToArray();
if (aliasAttributes.Any())
{
bindingContext.ValueProvider = new AliasValueProvider(bindingContext.ValueProvider,
bindingContext.ModelName, aliasAttributes.Select(attr => attr.Alias));
}
}
return base.BindProperty(bindingContext);
}
}
}
Provider:
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
namespace MYDOMAIN.Web.AliasModelBinder
{
public class AliasModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
{
var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
foreach (var property in context.Metadata.Properties)
{
propertyBinders.Add(property, context.CreateBinder(property));
}
return new AliasModelBinder(propertyBinders,
(ILoggerFactory) context.Services.GetService(typeof(ILoggerFactory)), true);
}
return null;
}
/// <summary>
/// Setup the AliasModelBinderProvider Mvc project to use BindingAlias attribute, to allow for aliasing property names in query strings
/// </summary>
public static void Configure(MvcOptions options)
{
// Place in front of ComplexTypeModelBinderProvider to replace this binder type in practice
for (int i = 0; i < options.ModelBinderProviders.Count; i++)
{
if (options.ModelBinderProviders[i] is ComplexTypeModelBinderProvider)
{
options.ModelBinderProviders.Insert(i, new AliasModelBinderProvider());
return;
}
}
options.ModelBinderProviders.Add(new AliasModelBinderProvider());
}
}
}
Value Provider:
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Primitives;
namespace MYDOMAIN.Web.AliasModelBinder
{
public class AliasValueProvider : IValueProvider
{
private readonly IValueProvider _provider;
private readonly string _originalName;
private readonly string[] _allNamesToBind;
public AliasValueProvider(IValueProvider provider, string originalName, IEnumerable<string> aliases)
{
_provider = provider;
_originalName = originalName;
_allNamesToBind = new[] {_originalName}.Concat(aliases).ToArray();
}
public bool ContainsPrefix(string prefix)
{
if (prefix == _originalName)
{
return _allNamesToBind.Any(_provider.ContainsPrefix);
}
return _provider.ContainsPrefix(prefix);
}
public ValueProviderResult GetValue(string key)
{
if (key == _originalName)
{
var results = _allNamesToBind.Select(alias => _provider.GetValue(alias)).ToArray();
StringValues values = results.Aggregate(values, (current, r) => StringValues.Concat(current, r.Values));
return new ValueProviderResult(values, results.First().Culture);
}
return _provider.GetValue(key);
}
}
}
And an attribute to go in / be referenced by the client project
using System;
namespace MYDOMAIN.Client
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class BindingAliasAttribute : Attribute
{
public string Alias { get; }
public BindingAliasAttribute(string alias)
{
Alias = alias;
}
}
}
Configured in the Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services
...
.AddMvcOptions(options =>
{
AliasModelBinderProvider.Configure(options);
...
})
...
Usage:
public class SomeRequest
{
[BindingAlias("f")]
public long[] SomeVeryLongNameForSomeKindOfFoo{ get; set; }
}
leading to a request that looks either like this:
api/controller/action?SomeVeryLongNameForSomeKindOfFoo=1&SomeVeryLongNameForSomeKindOfFoo=2
or
api/controller/action?f=1&f=2
I put most things in my web project, and the attribute in my client project.
I am trying to use the method of binding located here but having no luck
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Keep in mind I am not trying to do it this way:https://gist.github.com/akimboyko/4593576
Rather I am trying to use the convention GetMercedes() to mean
I am basically trying to achieve this:https://gist.github.com/akimboyko/4593576 with conventions specified in the above examples.
using Ninject;
using Ninject.Extensions.Factory;
using Ninject.Modules;
using Ninject.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Test.NinjectFactory
{
public class Program
{
public static void Main()
{
using (var kernel = new StandardKernel(new CarModule()))
{
var factory = kernel.Get<ICarFactory>();
var mercedes =factory.GetMercedes();
int i = 1;
}
}
public interface ICar
{
void Drive();
}
public class Mercedes : ICar
{
readonly ICarFactory carFactory;
public Mercedes(ICarFactory carFactory)
{
this.carFactory = carFactory;
}
public void Drive()
{
var Mercedes = this.carFactory.GetMercedes();
}
}
public interface ICarFactory
{
ICar GetMercedes();
}
public class CarModule : NinjectModule
{
public override void Load()
{
//https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Kernel.Bind<ICarFactory>().ToFactory();
Bind<ICar>().To<Mercedes>().NamedLikeFactoryMethod<ICarFactory>(x => x.GetMercedes());//doesnt work for me
}
}
}
}
I'm posting this as an answer because it is most likely the cause.
The factory extensions use prefixed Get methods as a standard. You'll run into issues by calling any of your factory methods with prefixed Get and using NamedLikeFactoryMethod. For example, GetFord, GetMercedes, GetNissan. You'll notice that, in the example at the link you provided, the function is called CreateMercedes.
Change your function name to CreateMercedes or anything that doesn't start with Get and it should be fine.
I found the anwswer here:
https://gist.github.com/akimboyko/5338320
It seems you need a function to take care of the binding
public class BaseTypeBindingGenerator<InterfaceType> : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type != null && !type.IsAbstract && type.IsClass && typeof(InterfaceType).IsAssignableFrom(type))
{
string.Format("Binds '{0}' to '{1}' as '{2}", type, type.Name, typeof(InterfaceType)).Dump();
yield return bindingRoot.Bind(typeof(InterfaceType))
.To(type)
.Named(type.Name) as IBindingWhenInNamedWithOrOnSyntax<object>;
}
}
}
I have been trying to create a calculated property in my persistence layer by follow
Hendry Luk's solution for calculated properties.
I am able to select the values from the DB using a linq query:
var result = from parcel in Repository.Query();
When I try to do a where on the selected result, I get a could not resolve property error.
Here is what my code looks like.
My Model:
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
public class Common1 : ICommon
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//public static readonly Expression<Func<Common1, string>> CalculatedDisplayExpression = x => ("Common 1 Display: " + x.Id + " - " + x.Name);
public static readonly Expression<Func<Common1, string>> CalculatedDisplayExpression = x => (x.Id + "");
private static readonly Func<Common1, string> CalculateDisplay = CalculatedDisplayExpression.Compile();
public virtual string Display { get { return CalculateDisplay(this); } }
}
}
My Interface the model implementing:
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;`enter code here`
public interface ICommon
{
int Id { get; set; }
string Name { get; set; }
string Display { get; }
}
}
Model's mapping
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping.ByCode.Conformist;
public class Common1Map : ClassMapping<Common1>
{
public Common1Map()
{
Id(x => x.Id, map => map.Generator(Generators.Native));
Property(x => x.Name);
}
}
}
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using NHibernate.Hql.Ast;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
using NHibernate.Linq.Visitors;
public class CalculatedPropertyGenerator<T, TResult> : BaseHqlGeneratorForProperty
{
public static void Register(ILinqToHqlGeneratorsRegistry registry, Expression<Func<T, TResult>> property, Expression<Func<T, TResult>> calculationExp)
{
registry.RegisterGenerator(ReflectionHelper.GetProperty(property), new CalculatedPropertyGenerator<T, TResult> { _calculationExp = calculationExp });
}
private CalculatedPropertyGenerator() { }
private Expression<Func<T, TResult>> _calculationExp;
public override HqlTreeNode BuildHql(MemberInfo member, Expression expression, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return visitor.Visit(_calculationExp);
}
}
}
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping;
using Iesi.Collections.Generic;
using System.Reflection;
using NHibernate.Linq.Functions;
using NHibernate.Linq;
public class SessionProvider
{
private static ISessionFactory sessionFactory;
public static SessionProvider Instance { get; private set; }
//DefaultLinqToHqlGeneratorsRegistry registry = new DefaultLinqToHqlGeneratorsRegistry();
ILinqToHqlGeneratorsRegistry registry = new DefaultLinqToHqlGeneratorsRegistry();
static SessionProvider()
{
var provider = new SessionProvider();
provider.Initialize();
Instance = provider;
}
private SessionProvider() { }
private void Initialize()
{
const string connString = "server=(local)\\mssql2008;database=Common;integrated security=sspi";
Configuration configuration = new Configuration();
configuration
.DataBaseIntegration(db =>
{
db.ConnectionString = connString;
db.Dialect<MsSql2008Dialect>();
db.Driver<SqlClientDriver>();
db.LogSqlInConsole = true;
db.IsolationLevel = System.Data.IsolationLevel.ReadCommitted;
})
.AddDeserializedMapping(GetMappings(), null);
CalculatedPropertyGenerator<Common1, string>.Register(registry, x => x.Display, Common1.CalculatedDisplayExpression);
// registry.RegisterGenerator(ReflectionHelper.GetProperty<Common1, string>(x => x.Display), new CalculatedPropertyGenerator());
var exporter = new SchemaExport(configuration);
exporter.Execute(true, true, false);
sessionFactory = configuration.BuildSessionFactory();
}
private HbmMapping GetMappings()
{
ModelMapper mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetAssembly(typeof(Common1Map)).GetExportedTypes());
HbmMapping mappings = mapper.CompileMappingForAllExplicitlyAddedEntities();
return mappings;
}
public ISession OpenSession()
{
return sessionFactory.OpenSession();
}
}
}
Client:
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
public class Tester
{
private ILinqToHqlGeneratorsRegistry registry = new DefaultLinqToHqlGeneratorsRegistry();
public void Go()
{
using (ISession session = SessionProvider.Instance.OpenSession())
{
CreateData(session);
IQueryable<ICommon> commons = session.Query<ICommon>();//.Where(x => x.Display.Contains("Common1 #7"));
var common1 = session.Query<Common1>().Where(x => x.Display.Contains("Common1 #7"));
foreach(var common in commons)
{
Console.WriteLine(common.Display);
}
}
}
private void CreateData(ISession session)
{
using (ITransaction tx = session.BeginTransaction())
{
for (int i = 0; i < 10; i++)
{
session.SaveOrUpdate(new Common1() { Name = "Common1 #" + i });
}
tx.Commit();
}
}
}
}
Register in SessionProvider class, like
configuration.LinqToHqlGeneratorsRegistry<MyLinqToHqlGeneratorsRegistry>();
MyLinqToHQLGeneratorRegistry implementation looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Linq.Functions;
using NHibernate.Linq;
namespace ConsoleApplication14
{
public class MyLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqToHqlGeneratorsRegistry()
: base()
{
CalculatedPropertyGenerator<Common1, string>.Register(this, x => x.Display, Common1.CalculatedDisplayExpression);
}
}
}
You need to derive a class from DefaultLinqToHqlGeneratorsRegistry. Add the registration logic in its constructor (passing 'this' to CalculatedPropertyGenerator<>.Register()). Then register the class with the NHibernate configuration using:
cfg.LinqToHqlGeneratorsRegistry<OurLinqFunctionRegistry>();
This is my first WCF Server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
namespace Myns.MBClient
{
[ServiceContract]
public interface IManagementConsole
{
[OperationContract]
ConsoleData GetData(int strategyId);
}
[ServiceContract]
public class ConsoleData
{
private int currentIndicator;
[OperationContract]
public double GetCurrentIndicator()
{
return currentIndicator;
}
public void SetCurrentIndicator(int currentIndicator)
{
this.currentIndicator = currentIndicator;
}
}
class ManagementConsole : IManagementConsole
{
public ConsoleData GetData(int strategyId)
{
ConsoleData data = new ConsoleData();
data.SetCurrentIndicator(33);
return data;
}
}
}
In client I just call pipeProxy.GetData(0).GetCurrentIndicator()
Why program prints 0 while it supposed to print 33?
Client code (which I think has no problems):
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using Commons;
using myns.MBClient;
namespace myns.MBClientConsole
{
class Program
{
static void Main(string[] args)
{
ChannelFactory<IManagementConsole> pipeFactory =
new ChannelFactory<IManagementConsole>(
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipeMBClientManagementConsole"));
IManagementConsole pipeProxy =
pipeFactory.CreateChannel();
while (true)
{
string str = Console.ReadLine();
Console.WriteLine("pipe: " +
pipeProxy.GetData(0).GetCurrentIndicator());
}
}
}
}
If you create your own complex type to use with WCF you have to add a DataContract attribute instead of a ServiceContract, and you should use fields/properties that are decorated with DataMember. And do yourself a favor and use plain DTOs (DataTransferObjects - Objects with only fields/properties but no behavior):
[DataContract]
public class ConsoleData
{
[DataMember]
public int CurrentIndicator {get;set;}
}
You can find more on this here