Using .net core I'm implementing class library to push bulk emails into Email server.Email server will consume my email list and gives feedback after complete.this will take 20-30 seconds.When I got feedback from email server I need to fire method.
I have referred this article to implement event handler.But when I debug it
EventHandler OnFeedbackReceived
parameter is null.see image below
This is class library code.
using System;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Collections.Generic;
namespace OSH_EmailServerLibrary
{
public static class EmailMQServerLibrary
{
public static event EventHandler<EmailFeedbackEventArgs> OnFeedbackReceived;
public static void PushToMQ(List<EmailMessage> _emailList)
{
//
// Long RabbitMQ msg push code here
//
EmailMessageFeedback feedback = new EmailMessageFeedback { Description = "Completed", SuccessCount = 10, FailedCount = 0 };
SendFeedback(feedback);
Console.ReadLine();
}
private static EmailMessageFeedback SendFeedback(EmailMessageFeedback feedback)
{
if (OnFeedbackReceived != null)
{
OnFeedbackReceived(feedback, new
EmailFeedbackEventArgs(feedback));
}
return feedback;
}
}
public class EmailFeedbackEventArgs : EventArgs
{
public EmailFeedbackEventArgs(EmailMessageFeedback _feedback)
{
feedback = _feedback;
}
public EmailMessageFeedback feedback { get; set; }
}
}
This is how I user it in a console application
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using OSH_EmailServerLibrary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace EmailServerSenderSampleConsole
{
class Program
{
static void Main(string[] args)
{
List<EmailMessage> _emailList = _emails.GetAllEmailToSend();
EmailMQServerLibrary.PushToMQ(_emailList);
EmailMQServerLibrary.OnFeedbackReceived += EmailMQServerLibrary_OnFeedbackReceived;
}
private static void EmailMQServerLibrary_OnFeedbackReceived(object sender, EmailFeedbackEventArgs e)
{
}
}
}
Finally Fixed my issue.Issue was not in my class library.Issue was I did subscribe event after PushToMQ() in my console application which is wrong..Thank you so much #Hans Passant helping me out.
here is my corrected answer.I think this will help others like me.
Class Library >>
using System;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Collections.Generic;
namespace OSH_EmailServerLibrary
{
public static class EmailMQServerLibrary
{
public static event EventHandler<EmailFeedbackEventArgs> OnFeedbackReceived;
public static void PushToMQ(List<EmailMessage> _emailList)
{
//
// Long RabbitMQ msg push code here
//
EmailMessageFeedback feedback = new EmailMessageFeedback { Description = "Completed", SuccessCount = 10, FailedCount = 0 };
SendFeedback(feedback);
Console.ReadLine();
}
private static EmailMessageFeedback SendFeedback(EmailMessageFeedback feedback)
{
if (OnFeedbackReceived != null)
{
OnFeedbackReceived(feedback, new
EmailFeedbackEventArgs(feedback));
}
return feedback;
}
}
public class EmailFeedbackEventArgs : EventArgs
{
public EmailFeedbackEventArgs(EmailMessageFeedback _feedback)
{
feedback = _feedback;
}
public EmailMessageFeedback feedback { get; set; }
}
}
Console Application >>
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using OSH_EmailServerLibrary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace EmailServerSenderSampleConsole
{
class Program
{
static void Main(string[] args)
{
List<EmailMessage> _emailList = _emails.GetAllEmailToSend();
EmailMQServerLibrary.OnFeedbackReceived +=
EmailMQServerLibrary_OnFeedbackReceived; //-- worked
EmailMQServerLibrary.PushToMQ(_emailList);
//EmailMQServerLibrary.OnFeedbackReceived +=
EmailMQServerLibrary_OnFeedbackReceived; -- Not working like this
}
private static void EmailMQServerLibrary_OnFeedbackReceived(object sender, EmailFeedbackEventArgs e)
{
}
}
}
Related
So i have this really annoying problem where i Can't seem to get it to update any of the databases i have created, whats worse the i can see the instance is showing the updated information but isn't applying it. I'm really new to this and is my first course project.
This is the code that is being used to update the data:
'''
using Project.Database;
using Project.DataClasses;
using Project.Pages.SuperPages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Project.Pages.UpdateDeleteListItem
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class UpdateDeleteList : ContentPage
{
private new readonly Label Title;
private Style LabelStyle;
private StoreDetails UpdateStoreDetails;
private Entry SNum;
private Entry SName;
private Entry SMName;
private Entry Addy;
public UpdateDeleteList(string pageType, object Item)
{
InitializeComponent();
BindingContext = Item;
UpdateStoreDetails = (StoreDetails)Item;
SetLabelStyle();
string titleMsg = "Update or Delete Selected " + pageType;
Frame frame = new Frame();
Label title = new Label() {Text = titleMsg };
Title = title;
StackLayout titleStack = new StackLayout() { Children = { Title } };
frame.Content = titleStack;
if (pageType == "Store")
{
StoreUDLItem(frame);
}
if (pageType == "Ticket")
{
TicketUDLItem(frame);
}
StylePage();
}
private void SaveButton_Clicked(object sender, EventArgs args)
{
if (StoreCheckValues() == true)
{
var store = SName;
var storeManager = SMName;
var storeNumber = SNum;
var address = Addy;
var storeDataAccess = new StoreDataAccess();
UpdateStoreDetails.StoreName = store.Text;
UpdateStoreDetails.StoreManger = storeManager.Text;
UpdateStoreDetails.StoreNumber = storeNumber.Text;
UpdateStoreDetails.Address = address.Text;
//MerchandiserKey = GetMerchId()
storeDataAccess.SaveStoreDetails(UpdateStoreDetails);
storeDataAccess.SaveAllStoreDetails();
}
'''
here is the data access methods:
'''
using Project.DataClasses;
using SQLite;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using Xamarin.Forms;
namespace Project.Database
{
class StoreDataAccess
{
private SQLiteConnection database;
private static object collisionLock = new object();
public ObservableCollection<StoreDetails> StoreDetails { get; set; }
public StoreDataAccess()
{
database = DependencyService.Get<IDatabaseConnection>().DbConnectionStore();
database.CreateTable<StoreDetails>();
this.StoreDetails = new ObservableCollection<StoreDetails>(database.Table<StoreDetails>());
//AddNewTicket(new Ticket ticket);
}
//add ticket method
public void AddNewStore(StoreDetails item)
{
this.StoreDetails.Add(item);
}
//retrieve ticket method
public StoreDetails GetStoreDetails(int id)
{
lock (collisionLock)
{
return database.Table<StoreDetails>().FirstOrDefault(StoreDetails => StoreDetails.StoreId == id);
}
}
//save ticket
public int SaveStoreDetails(StoreDetails storeDetailsInstance)
{
lock (collisionLock)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
else
{
database.Insert(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
//database.Commit();
}
}
public void SaveAllStoreDetails()
{
lock (collisionLock)
{
foreach (var storeDetailsInstance in this.StoreDetails)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
}
else
{
database.Insert(storeDetailsInstance);
}
}
}
}
'''
This is the page that is sending the information to the first code block to bind the data too
'''
using Project.Database;
using Project.DataClasses;
using Project.Pages.UpdateDeleteListItem;
using SQLite;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Project.Pages.ListPages
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StoreList : ContentPage
{
private ObservableCollection<StoreDetails> Items { get; set; }
private readonly StoreDataAccess storeDataAccess;
private readonly SQLiteConnection database;
public StoreList()
{
InitializeComponent();
storeDataAccess = new StoreDataAccess();
this.BindingContext = this.storeDataAccess;
Items = storeDataAccess.StoreDetails;
StoreView.ItemsSource = Items;
}
async void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e.Item == null) { return; }
else
{
//var id = Items[e.ItemIndex].StoreId;
await Navigation.PushAsync(new UpdateDeleteList("Store", e.Item));
//Deselect Item
((ListView)sender).SelectedItem = null;
}
}
//page reload handle
protected override void OnAppearing()
{
base.OnAppearing();
var dbName = "StoreListDatabase.db3";
var path = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Personal), dbName);
if (database == null)
{
new StoreDataAccess();
}
using (SQLiteConnection conn = new SQLiteConnection(path))
{
Items = storeDataAccess.StoreDetails;
StoreView.ItemsSource = Items;
}
}
}
}
'''
and lastly here is my databbase model for it:
'''
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using SQLite;
using System.ComponentModel;
namespace Project.DataClasses
{
class StoreDetails : INotifyPropertyChanged
{
private int _storeId;
[PrimaryKey, AutoIncrement, NotNull]
public int StoreId
{
get { return _storeId; }
set { _storeId = value; OnPropertyChanged(nameof(StoreId)); }
}
private string _storeName;
[NotNull, DefaultValue("Enter Store Name")]
public string StoreName
{
get { return _storeName; }
set { _storeName = value; OnPropertyChanged(nameof(_storeName)); }
}
private string _storeManger;
[NotNull, DefaultValue("Enter Store Managers Name")]
public string StoreManger
{
get { return _storeManger; }
set { _storeManger = value; OnPropertyChanged(nameof(StoreManger)); }
}
private string _storeNumber;
[NotNull, DefaultValue("Enter Store Number")]
public string StoreNumber
{
get { return _storeNumber; }
set { _storeNumber = value; OnPropertyChanged(nameof(StoreNumber)); }
}
private string _address;
[NotNull, DefaultValue("Enter Address")]
public string Address
{
get { return _address; }
set { _address = value; OnPropertyChanged(nameof(Address)); }
}
private int _merchandiserKey;
[NotNull]
public int MerchandiserKey
{
get { return _merchandiserKey; }
set { _merchandiserKey = value; OnPropertyChanged(nameof(MerchandiserKey)); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
'''
any help would be greatly appreciated
'''
public int SaveStoreDetails(StoreDetails storeDetailsInstance)
{
lock (collisionLock)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
else
{
database.Insert(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
//database.Commit();
}
}
'''
this is the area where it all seems to be going wrong i just don't know why
Thank You Jason, you were correct in that the error was in calling both the savefunctions and overwriting it!!
I am using xamarin forms for my app. I am using foreground service for my app to work on background. I kill the App and when I try to relaunch the App, I can't open the App. Here I am adding My service code below. Please see the code and give me suggestions to solve this issue.
My Service Code is below:
MyPrjService.cs:
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using System.Threading;
using System.Threading.Tasks;
using Android.Support.V4.App;
using Android;
using Android.Media;
using MyPrj.Interface;
using Xamarin.Forms;
using System.IO;
using Android.Net;
using MyPrj.Common;
using MyPrj.Services;
using Android.App;
using MyPrj.BusinessLogic;
using MyPrj.Helper;
using System;
using Plugin.Connectivity;
using MyPrj.Form;
using Android.Graphics;
namespace MyPrj.Droid.Services
{
[Service]
public class MyPrjService : Service
{
CancellationTokenSource _cts;
private static ILogger logger = DependencyService.Get<ILogManager>().GetLog();
public const string LOCATION_CHANNEL = "default";
NotificationManager manager;
NotificationCompat.Builder notification;
public override void OnCreate()
{
base.OnCreate();
manager = (NotificationManager)Forms.Context.GetSystemService("notification");
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
StartLocationServiceForeground();
return StartCommandResult.Sticky;
}
void StartLocationServiceForeground()
{
try
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var chan1 = new NotificationChannel(LOCATION_CHANNEL,
new Java.Lang.String("Primary"), NotificationImportance.High);
manager.CreateNotificationChannel(chan1);
notification = new NotificationCompat.Builder(Forms.Context, LOCATION_CHANNEL);
notification.SetOngoing(true)
//.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.icon))
.SetSmallIcon(Resource.Drawable.icon_transparent)
.SetContentTitle("MyPrj is running background")
.SetContentText("Tab for more information or to stop the app")
.SetColor(0x9c6114)
.SetPriority(NotificationCompat.PriorityHigh);
StartForeground(1, notification.Build());
}
}
catch(System.Exception ex)
{
}
}
public override void OnDestroy()
{
StopForeground(true);
if (manager!=null)
{
manager.CancelAll();
}
base.OnDestroy();
}
}
}
App.xaml.cs:
protected override async void OnSleep()
{
try
{
var context = Droid.MainActivity.Instance;
if (context != null)
{
context.StartServiceFromApp();
}
}
}
protected async override void OnResume()
{
var context = Droid.MainActivity.Instance;
if (context != null)
{
context.StopServiceFromApp();
}
}
MainActivity.cs:
public void StartServiceFromApp()
{
os 9
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var intent1 = new Intent(this, typeof(MyPrjService));
StartService(intent1);
}
}
public void StopServiceFromApp()
{
var intent1 = new Intent(this, typeof(ScoularService));
StopService(intent1);
}
I'd like to made an mobile application to do things after SMS is reveived.
I made an interface of the "SMS-Class" that defines all methods.
Then I made a Class in the Main Xamarin Forms project witch inherit from the interface (this way I can't miss to create any method).
Next I created a class in the Android part of the project witch should read (and more) SMS on receiving.
I called the mehtod of the android part with DependencyService from the class in the main project.
To manage the incomming SMS in android I did the following:
I made a method (in the Android project - "CheckForIncommingSMS") to register a BroadcastReceiver witch should be the calling class itself.
The mentioned method is called from the MainPage in the main project.
MainPage => SMSHelper.CheckForIncommingSMS() => Android Project => registring BroadcastReceiver for incomming SMS
Screenmessage when SMS received.
The Broadcast Receiver itself seems to work.
I tested it with other intentactions and it worked.
I found out that the OnReceive-method isn't called.
What did I wrong?
Thanks!
using System.Collections.Generic;
using App.Models;
namespace App.Services
{
public interface ISMSHelper
{
void CheckForIncommingSMS();
void Create(string sender, string receiver, string message);
void Send();
List<SMS> ReadAll();
SMS Get();
}
}
using System.Collections.Generic;
using App.Models;
using Xamarin.Forms;
// Class in Main Xamarin Forms Project
[assembly: Xamarin.Forms.Dependency(typeof(App.Services.SMSHelper))]
namespace App.Services
{
class SMSHelper : ISMSHelper
{
public void CheckForIncommingSMS()
{
DependencyService.Get<ISMSHelper>().CheckForIncommingSMS();
}
public void Create(string sender, string receiver, string message)
{
DependencyService.Get<ISMSHelper>().Create(sender, receiver, message);
}
public SMS Get()
{
return DependencyService.Get<ISMSHelper>().Get();
}
public List<SMS> ReadAll()
{
return DependencyService.Get<ISMSHelper>().ReadAll();
}
public void Send()
{
DependencyService.Get<ISMSHelper>().Send();
}
}
}
//Class in Xamarin Forms Project (Android)
using Android.App;
using Android.Content;
using Android.Provider;
using Android.Telephony;
using Android.Util;
using Android.Widget;
using Plugin.Messaging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using App.Models;
using App.Services;
using Xamarin.Forms;
[assembly: Xamarin.Forms.Dependency(typeof(App.Droid.SMSHelper))]
namespace App.Droid
{
[BroadcastReceiver(Enabled = true, Label = "SMS Receiver")]
[IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" })]
public class SMSHelper : BroadcastReceiver, ISMSHelper
{
private const string Tag = "SMSBroadcastReceiver";
private const string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
SMS sms = new SMS();
public SMSHelper() {
/* https://blog.xamarin.com/cross-platform-messaging-for-ios-android-and-windows https://forums.xamarin.com/discussion/13682/broadcastreceiver-for-sms*/}
public void Create(string sender, string receiver, string message)
{
sms.Sender = sender;
sms.Receiver = receiver;
sms.Message = message;
}
public void Send()
{
if ((!sms.Receiver.Equals("")) && (!sms.Message.Equals("")))
{
var smsMessenger = CrossMessaging.Current.SmsMessenger;
if (smsMessenger.CanSendSmsInBackground)
{
smsMessenger.SendSmsInBackground(sms.Receiver, sms.Message);
}
}
}
public SMS Get()
{
return sms;
}
public List<SMS> ReadAll()
{
throw new System.NotImplementedException();
}
public override void OnReceive(Context context, Intent intent)
{
Log.Info(Tag, "Intent received: " + intent.Action);
if (intent.Action != IntentAction) return;
SmsMessage[] messages = Telephony.Sms.Intents.GetMessagesFromIntent(intent);
for (var i = 0; i < messages.Length; i++)
{
sms.Sender = messages[i].OriginatingAddress;
sms.Message = messages[i].MessageBody;
sms.Timestamp = DateTime.Now;
Toast.MakeText(context, sms.Message, ToastLength.Long).Show();
Debug.WriteLine("SMS ER");
}
Toast.MakeText(context, "sdfghhj", ToastLength.Long).Show();
}
public void CheckForIncommingSMS()
{
Debug.WriteLine("HALLO");
Forms.Context.RegisterReceiver(this, new IntentFilter(IntentAction));
}
}
}
I have google a lot about building CustomRenderer to display custom navigationpage on xamarin form (to display gradient on navigationbar) but did not succeed.
here is my code:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace BillerApp
{
public class GradientNavigationBar: NavigationPage
{
public GradientNavigationBar(Page page): base(page)
{
}
public GradientNavigationBar() : base()
{
}
public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
nameof(StartColor),
typeof(Color),
typeof(GradientNavigationBar),
Color.Default);
public static readonly BindableProperty EndColorProperty = BindableProperty.Create(
nameof(EndColor),
typeof(Color),
typeof(GradientNavigationBar),
Color.Default);
public Color StartColor {
get { return (Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
public Color EndColor
{
get { return (Color)GetValue(EndColorProperty); }
set { SetValue(EndColorProperty, value); }
}
}
}
and following is the renderer on Xamarin.Droid
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using BillerApp;
using Xamarin.Forms.Platform.Android;
using Android.Graphics.Drawables;
using BillerApp.Droid;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(GradientNavigationBar), typeof(GrandientNavigationBarRenderer))]
namespace BillerApp.Droid
{
[Activity(Name = "com.companyname.BillerApp.MainActivity")]
public class GrandientNavigationBarRenderer: Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer
{
//public GrandientNavigationBarRenderer(Context context): base(context){} //can not use this constructor
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e); // I got Invalid Cast Exception if Inherit from NavigationRenderer
if (e.OldElement != null || Element == null)
{
return;
}
var p = this.Element as GradientNavigationBar;
var context = (Activity)this.Context;
var sc = new int[] { p.StartColor.ToAndroid(), p.EndColor.ToAndroid() };
var grad = new GradientDrawable(GradientDrawable.Orientation.TopBottom, sc);
var t = context.ActionBar; // here i got null
t.SetSplitBackgroundDrawable(grad);
context.ActionBar.SetBackgroundDrawable(grad);
}
}
}
this is what i am trying to achieve:
I am using VS 2015 Community edition and have updated SDK tools to date
I would do it simply by adding something like this to your layout folder:
toolbar_gradient.xml
<gradient
android:type="linear"
android:startColor="#F3A183"
android:endColor="#EC6F66"
android:angle="270"/>
</shape>
Then in your Toolbar.xml add this line of code:
android:background="#layout/toolbar_gradient"
I'm using the latest version of WebApi and OData and everything is set up to work right. The only problem is when I try to use $select .
It throws the error bellow
Object of type 'System.Linq.EnumerableQuery`1[System.Web.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[WebApplication1.Controllers.Person]]' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[WebApplication1.Controllers.Person]'.
I looked at the documentation and their suggestion is to use [Queryable] on top of the Get method in the controller or the in WebApiConfig to use config.EnableQuerySupport and neither of these are available options. I'm currently using [EnableQuery]
EDIT
OdataController:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.OData;
using System.Xml.Serialization;
namespace WebApplication1.Controllers
{
public class PeopleController : ODataController
{
// GET api/values
[EnableQuery]
public IQueryable<Person> Get()
{
return new Person[] { new Person()
{
Id = 1,
FirstName = "Testing",
LastName = "2"
}, new Person()
{
Id = 2,
FirstName = "TestTest",
LastName = "3"
} }.AsQueryable();
}
// GET api/values/5
public Person Get(int id)
{
return new Person()
{
Id = 3,
FirstName = "Test",
LastName = "1"
};
}
// POST api/values
public void Post([FromBody]Person value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]Person value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
public class Person
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
WebApiConfig
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using System.Web.OData.Formatter;
using WebApplication1.Controllers;
namespace WebApplication1
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
var odataFormatters = ODataMediaTypeFormatters.Create();
config.Formatters.InsertRange(0, odataFormatters);
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Person>("People");
config.AddODataQueryFilter();
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "api",
model: builder.GetEdmModel());
}
}
}
UPDATE 2
seems to only throw an error retrieving the data in xml format. Json seems to work
This is a known limitation of the XmlMediaTypeFormatter class from the System.Net.Formatting Nuget package. The implementation of the JSON formatter does support the $select and $expand commands but these are not available when content negotiation determines that XML should be returned.
You should look into implementing OData endpoints (as opposed to WebAPI endpoints) should you need to return XML formatted responses. More information on how this can be done can be found here:
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options
Found a solution. It isn't perfect but it does work!
Maybe it will be useful for someone because I've spent on it few hours of research and trying.
Step #1 create custom xml formatter:
public class CustomXmlFormatter : MediaTypeFormatter
{
private JsonMediaTypeFormatter jFormatter = null;
public CustomXmlFormatter(JsonMediaTypeFormatter jFormatter)
{
SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml"));
this.jFormatter = jFormatter;
}
public override bool CanReadType(Type type)
{
return false;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
{
return Task.Factory.StartNew(() =>
{
using (MemoryStream ms = new MemoryStream())
{
var tsk = jFormatter.WriteToStreamAsync(type, value, ms, content, transportContext);
tsk.Wait();
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
var xDoc = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(ms, new XmlDictionaryReaderQuotas()));
using (XmlWriter xw = XmlWriter.Create(writeStream))
{
xDoc.WriteTo(xw);
}
}
});
}
}
Step #2 register it in startup section:
var formatters = ODataMediaTypeFormatters.Create();
var jsonFormatter = config.Formatters.JsonFormatter;
var customXmlFormatter = new CustomXmlFormatter(jsonFormatter);
customXmlFormatter.AddQueryStringMapping("$format", "cxml", "application/xml");
config.Formatters.Add(customXmlFormatter);
use it as
http://url..../actionName?$format=cxml&$select=ObjectName,ObjectId